Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2233238/?format=api
{ "id": 2233238, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2233238/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260505223045.347444-4-feedabl3@gmail.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.2/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260505223045.347444-4-feedabl3@gmail.com>", "list_archive_url": null, "date": "2026-05-05T22:30:45", "name": "[RFC,2/3] wasm: New backend", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "95c8fc5e49e491128b5f5152dfec51794db86870", "submitter": { "id": 92146, "url": "http://patchwork.ozlabs.org/api/1.2/people/92146/?format=api", "name": "feedable", "email": "feedabl3@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260505223045.347444-4-feedabl3@gmail.com/mbox/", "series": [ { "id": 502902, "url": "http://patchwork.ozlabs.org/api/1.2/series/502902/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502902", "date": "2026-05-05T22:30:44", "name": "wasm: New backend", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/502902/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2233238/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2233238/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=XrH6drT/;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=XrH6drT/", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "sourceware.org; spf=pass smtp.mailfrom=gmail.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=2a00:1450:4864:20::332" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g9Ctc5Mg6z1yJq\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 08:32:08 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id DA5694BA23E0\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 5 May 2026 22:32:06 +0000 (GMT)", "from mail-wm1-x332.google.com (mail-wm1-x332.google.com\n [IPv6:2a00:1450:4864:20::332])\n by sourceware.org (Postfix) with ESMTPS id B188E4BA2E0B\n for <gcc-patches@gcc.gnu.org>; Tue, 5 May 2026 22:31:14 +0000 (GMT)", "by mail-wm1-x332.google.com with SMTP id\n 5b1f17b1804b1-48374014a77so68145385e9.3\n for <gcc-patches@gcc.gnu.org>; Tue, 05 May 2026 15:31:14 -0700 (PDT)", "from 7a38.moduleworks.com\n ([2a02:8308:900b:fc00:1c70:a43b:cde8:2b29])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48e53559d8esm79055e9.9.2026.05.05.15.31.12\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 05 May 2026 15:31:12 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org DA5694BA23E0", "OpenDKIM Filter v2.11.0 sourceware.org B188E4BA2E0B" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org B188E4BA2E0B", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org B188E4BA2E0B", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020275; cv=none;\n b=UxmKUQXOS3YXPgnF0nBjUKKd7AfqKyPPCxWhc4oVXort3ibbynHlMjnzvdjTZ4OmOnHnOYHN4XkMLh1Hk9uxUeA09ZObAVoYtFz0rYNpkHpOpIgq9pI4ij/k/K6twvrtnT1ziZDEnoN4IG0vpCk/468UF+p+IdoMVNMk5DG3Cw8=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778020275; c=relaxed/simple;\n bh=JgKXPP4fU332g85dnBKu4CxtRI+MHCrBa71GVxKv0Lo=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=wJM6aotmCfjyBLkBcgynzM/GHM8GrZQbi1cMHDYue/8s8fKU2M7TpresSrQLSDMPZbCKh2XlFAnB0wzDGFUu1RcEBIzSnmuiX72g1xsSApArVxRToOsVRcd6/foOOgzro1ZdXBk4iNk7cbd37KgCRoiGFJCMcnQKG5cEQQf8pEM=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1778020274; x=1778625074; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=W3QSTVW1UGuUKD3F7Lu9UQBQNB46kPkQR2OrFYI4TMM=;\n b=XrH6drT/z4FdA8871XNdhz4AhnxkyQx5Qqp5Irt/sjMrrSAu0/6OJnZWANM8vT+vIb\n hYJ+b+Lfg6jacMRsQumLY3PCNlW3HfwIRShTgOEsOkb6KZik/kgHZick02sJvk5SxTPt\n nQxoCEkKfJst/z57kGMhNdnb472n2KNeHtb5QH7TH5P5zLrsTJiOvlfzDXzn/eHI8ssy\n NXoaXmFh/e+IWBhjwYiGn/JJFvvx+r6efr/YVwmnDXH/UpkR496uf7a9CKJnwv77T+Fk\n cX32Aeq8wZ+S3ZzhzWwcpOA1gsgngPT8YNEE60VJA9SK6WlocCesUxIYDX4xmsVOJq3p\n Un3g==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778020274; x=1778625074;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=W3QSTVW1UGuUKD3F7Lu9UQBQNB46kPkQR2OrFYI4TMM=;\n b=YBhGwhVqOdeawiQ5LobATkde1Pxi16/PfWpzxeQQet6rg6DxcQKn3f1PkAcAeqBH1s\n 7pWDsBVcHiG4dtKFDViK/7Z19PWn2Tbq0q/YQkKkaw2kXcMRVXOIQuZCiYbYXwym1t9c\n 1yXNXFfuB/EJamdjQelhCH6ULPaHgUikqUCFGkOYTeGPZhkWKLIu/6Kv+00jKqyCccP+\n 5wBY5V6N5CbB8tL4MQ4i5+Z7Dg28VNS/II2GzmFzhSoGyzfVVkRxDWcnhMwaHcQlVRA2\n LWFzHsqpSOWU0nT5tQ/JFQDf+LV+17lt2hpLLfH/9DInsWlgmhax1rgkwKxzJ3mRT8LM\n dvIA==", "X-Gm-Message-State": "AOJu0YzPG1VhJdil/M/O8ZX+IqfP3rZxZk1GXQYmyAjR9WhI4TixMx0d\n Sl0v6Q+6HUHURDPT7QsVdbVvsDzNXJn/X1SnEIQ2Pm6L5YpyWtiKzjF0B2xqZA==", "X-Gm-Gg": "AeBDiesq7wZ2i3F9+HUwoHvMaw+MVZg2X5zdDavdEST3SCAH3sdu4pI+3ACoziHDZON\n viM+P3StXalBrEwmqYjbowBw0AG6rtSiNZTRtMemR0nSHonfA7SuyKV2Gtm4arXQCAumV8UkJRg\n iECrTwjy+Tg5QIJo+p9diJns2gMDFRyyfjznQUQG90HRmGxlcGvzMIBOfZms1b1GDEZVAaHg9nu\n GoTO9hdM4/MMh6tDnHS0xi/g4ADpvbCSKWwZb9U3/CjT38FZzI+z9HjkFnR01ZeVXnSaLaKhrtO\n fcWFru+jleS4n9o/dn1u9x0Pchxz39y+yTZG6rDrWIBY7SPbpC7uyYvBEzsIrpuFIHtSVmHpgs4\n PMTmjuRsTFXOEf6Qq4v4dlhEN0xZbLOj9LHdupRh5PlwxIAVlyAYQtPIbHCZZkZxcdPcjobVFEr\n 9Beqf6Wf9I5HJhvywgWKZXlzbwwBuyU8aMvtNgzGbTIYQt5hd3/QgMW7iyPxk=", "X-Received": "by 2002:a05:600c:3b17:b0:48a:568f:ae6d with SMTP id\n 5b1f17b1804b1-48e51e15c37mr15996545e9.8.1778020273153;\n Tue, 05 May 2026 15:31:13 -0700 (PDT)", "From": "feedable <feedabl3@gmail.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "feedable <feedabl3@gmail.com>", "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", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "I don't really know what kind of a description is expected for a new backend\nimplementation, so I'm leaving this empty for now as a placeholder.\n\n-- 8< --\n\ngcc/ChangeLog:\n\n\t* config.gcc: Adjust for new backend.\n\t* config/wasm/attrs.md: New file.\n\t* config/wasm/t-wasm: New file.\n\t* config/wasm/wasm-asm.cc: New file.\n\t* config/wasm/wasm-cg.cc: New file.\n\t* config/wasm/wasm-modes.def: New file.\n\t* config/wasm/wasm-passes.cc: New file.\n\t* config/wasm/wasm-passes.def: New file.\n\t* config/wasm/wasm-protos.h: New file.\n\t* config/wasm/wasm.cc: New file.\n\t* config/wasm/wasm.h: New file.\n\t* config/wasm/wasm.md: New file.\n\nlibgcc/ChangeLog:\n\n\t* config.host: Adjust for new backend.\n\t* config/wasm/t-wasm: New file.\n---\n gcc/config.gcc | 7 +\n gcc/config/wasm/attrs.md | 84 +++\n gcc/config/wasm/t-wasm | 13 +\n gcc/config/wasm/wasm-asm.cc | 945 ++++++++++++++++++++++++++++++++\n gcc/config/wasm/wasm-cg.cc | 621 +++++++++++++++++++++\n gcc/config/wasm/wasm-modes.def | 0\n gcc/config/wasm/wasm-passes.cc | 153 ++++++\n gcc/config/wasm/wasm-passes.def | 27 +\n gcc/config/wasm/wasm-protos.h | 12 +\n gcc/config/wasm/wasm.cc | 128 +++++\n gcc/config/wasm/wasm.h | 307 +++++++++++\n gcc/config/wasm/wasm.md | 495 +++++++++++++++++\n libgcc/config.host | 5 +\n libgcc/config/wasm/t-wasm | 4 +\n 14 files changed, 2801 insertions(+)\n create mode 100644 gcc/config/wasm/attrs.md\n create mode 100644 gcc/config/wasm/t-wasm\n create mode 100644 gcc/config/wasm/wasm-asm.cc\n create mode 100644 gcc/config/wasm/wasm-cg.cc\n create mode 100644 gcc/config/wasm/wasm-modes.def\n create mode 100644 gcc/config/wasm/wasm-passes.cc\n create mode 100644 gcc/config/wasm/wasm-passes.def\n create mode 100644 gcc/config/wasm/wasm-protos.h\n create mode 100644 gcc/config/wasm/wasm.cc\n create mode 100644 gcc/config/wasm/wasm.h\n create mode 100644 gcc/config/wasm/wasm.md\n create mode 100644 libgcc/config/wasm/t-wasm", "diff": "diff --git a/gcc/config.gcc b/gcc/config.gcc\nindex d1595a1d85e..822515c127e 100644\n--- a/gcc/config.gcc\n+++ b/gcc/config.gcc\n@@ -614,6 +614,10 @@ tic6x-*-*)\n \textra_headers=\"c6x_intrinsics.h\"\n \textra_options=\"${extra_options} c6x/c6x-tables.opt\"\n \t;;\n+wasm*-*-*)\n+ cpu_type=wasm\n+ extra_objs=\"wasm-cg.o wasm-asm.o wasm-passes.o\"\n+ ;;\n xtensa*-*-*)\n \textra_options=\"${extra_options} fused-madd.opt\"\n \textra_objs=\"xtensa-dynconfig.o\"\n@@ -3677,6 +3681,9 @@ visium-*-elf*)\n \ttm_file=\"elfos.h ${tm_file} visium/elf.h newlib-stdint.h\"\n \ttmake_file=\"visium/t-visium visium/t-crtstuff\"\n \t;;\n+wasm*-*-*)\n+ target_has_targetm_common=no\n+ ;;\n xstormy16-*-elf)\n \t# For historical reasons, the target files omit the 'x'.\n \ttm_file=\"elfos.h newlib-stdint.h stormy16/stormy16.h\"\ndiff --git a/gcc/config/wasm/attrs.md b/gcc/config/wasm/attrs.md\nnew file mode 100644\nindex 00000000000..6fbe39e5ce7\n--- /dev/null\n+++ b/gcc/config/wasm/attrs.md\n@@ -0,0 +1,84 @@\n+(define_c_enum \"unspecv\" [\n+ UNSPECV_CALL_ADDRESS_BARRIER\n+])\n+\n+(define_mode_iterator QHSDI [QI HI SI DI])\n+(define_mode_iterator QHSDI2 [QI HI SI DI])\n+(define_mode_iterator QHSDISDF [QI HI SI DI SF DF])\n+(define_mode_iterator F [SF DF])\n+(define_mode_iterator REG [SI DI])\n+(define_mode_iterator REGF [SI DI SF DF])\n+(define_mode_attr REG2F [(SI \"SF\") (DI \"DF\") (SF \"SI\") (DF \"DI\")])\n+(define_mode_attr reg2f [(SI \"sf\") (DI \"df\") (SF \"si\") (DF \"di\")])\n+(define_mode_attr reg2f_types [\n+ (SF \"i32\") (DF \"i64\")\n+ (SI \"f32\") (DI \"f64\")])\n+(define_mode_attr types [\n+ (QI \"i8\") (HI \"i16\")\n+ (SI \"i32\") (DI \"i64\")\n+ (SF \"f32\") (DF \"f64\")])\n+(define_mode_attr size [\n+ (QI \"8\") (HI \"16\")\n+ (SI \"32\") (DI \"64\")\n+ (SF \"32\") (DF \"64\")])\n+(define_mode_attr promote_type [\n+ (QI \"i32\") (HI \"i32\")\n+ (SI \"i32\") (DI \"i64\")\n+ (SF \"f32\") (DF \"f32\")])\n+(define_mode_attr promote_mode [\n+ (QI \"SI\") (HI \"SI\")\n+ (SI \"SI\") (DI \"DI\")\n+ (SF \"SF\") (DF \"DF\")])\n+(define_mode_iterator SUBREGSI [QI HI])\n+(define_mode_iterator SUBREGDI [QI HI SI])\n+(define_mode_iterator P [(SI \"Pmode == SImode\") (DI \"Pmode == DImode\")])\n+\n+(define_code_iterator irelop [le ge lt gt leu geu ltu gtu eq ne])\n+(define_code_iterator frelop [le ge lt gt eq ne])\n+\n+(define_code_iterator iunop [clz ctz popcount])\n+\n+(define_code_iterator iconvop [sign_extend truncate])\n+\n+(define_code_iterator ibinop [\n+ and ior xor\n+ plus minus mult\n+ div udiv mod umod\n+ ashift ashiftrt lshiftrt\n+ rotate rotatert])\n+\n+(define_code_iterator fbinop [plus minus mult div smin smax copysign])\n+\n+(define_code_iterator funop [abs neg sqrt])\n+\n+(define_code_attr opname [\n+ (eq \"eq\") (ne \"ne\")\n+ (le \"le_s\") (ge \"ge_s\") (lt \"lt_s\") (gt \"gt_s\")\n+ (leu \"le_u\") (geu \"ge_u\") (ltu \"lt_u\") (gtu \"gt_u\")\n+ (clz \"clz\") (ctz \"ctz\") (popcount \"popcnt\")\n+ (and \"and\") (ior \"or\") (xor \"xor\")\n+ (plus \"add\") (minus \"sub\") (mult \"mul\")\n+ (div \"div_s\") (udiv \"div_u\") (mod \"rem_s\") (umod \"rem_u\")\n+ (ashift \"shl\") (ashiftrt \"shr_s\") (lshiftrt \"shr_u\")\n+ (rotate \"rotl\") (rotatert \"rotr\")\n+ (sign_extend \"extend\") (zero_extend \"zero_extend\")\n+ (truncate \"trunc\")\n+ (abs \"abs\") (neg \"neg\") (sqrt \"sqrt\")])\n+(define_code_attr opnamef [\n+ (eq \"eq\") (ne \"ne\") (le \"le\") (ge \"ge\") (lt \"lt\") (gt \"gt\")\n+ (plus \"add\") (minus \"sub\") (mult \"mul\") (div \"div\") (smin \"min\") (smax \"max\")\n+ (abs \"abs\") (neg \"neg\") (sqrt \"sqrt\") (copysign \"copysign\")])\n+(define_code_attr opname_rt [\n+ (eq \"eq\") (ne \"ne\")\n+ (le \"le\") (ge \"ge\") (lt \"lt\") (gt \"gt\")\n+ (leu \"leu\") (geu \"geu\") (ltu \"ltu\") (gtu \"gtu\")\n+ (clz \"clz\") (ctz \"ctz\") (popcount \"popcount\")\n+ (and \"and\") (ior \"ior\") (xor \"xor\")\n+ (plus \"add\") (minus \"sub\") (mult \"mul\")\n+ (div \"div\") (udiv \"udiv\") (mod \"mod\") (umod \"umod\")\n+ (ashift \"ashl\") (ashiftrt \"ashr\") (lshiftrt \"lshr\")\n+ (rotate \"rotl\") (rotatert \"rotr\")\n+ (sign_extend \"extend\") (zero_extend \"zero_extend\")\n+ (truncate \"ftrunc\")\n+ (smax \"smax\") (smin \"smin\") (copysign \"copysign\")\n+ (abs \"abs\") (neg \"neg\") (sqrt \"sqrt\")])\ndiff --git a/gcc/config/wasm/t-wasm b/gcc/config/wasm/t-wasm\nnew file mode 100644\nindex 00000000000..6d5846a8822\n--- /dev/null\n+++ b/gcc/config/wasm/t-wasm\n@@ -0,0 +1,13 @@\n+wasm-cg.o: $(srcdir)/config/wasm/wasm-cg.cc \\\n+ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H)\n+\t$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<\n+\n+wasm-asm.o: $(srcdir)/config/wasm/wasm-asm.cc \\\n+ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H)\n+\t$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<\n+\n+wasm-passes.o: $(srcdir)/config/wasm/wasm-passes.cc \\\n+ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H)\n+\t$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<\n+\n+PASSES_EXTRA += $(srcdir)/config/wasm/wasm-passes.def\n\\ No newline at end of file\ndiff --git a/gcc/config/wasm/wasm-asm.cc b/gcc/config/wasm/wasm-asm.cc\nnew file mode 100644\nindex 00000000000..17306a82851\n--- /dev/null\n+++ b/gcc/config/wasm/wasm-asm.cc\n@@ -0,0 +1,945 @@\n+/* WebAssembly assembly output utilities.\n+ Copyright (C) 2025-2025 Free Software Foundation, Inc.\n+ Contributed by feedable.\n+\n+ This file is part of GCC.\n+\n+ GCC is free software; you can redistribute it and/or modify\n+ it under the terms of the GNU General Public License as published by\n+ the Free Software Foundation; either version 3, or (at your option)\n+ any later version.\n+\n+ GCC is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ GNU General Public License for more details.\n+\n+ You should have received a copy of the GNU General Public License\n+ along with GCC; see the file COPYING3. If not see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#define IN_TARGET_CODE 1\n+\n+#include <limits>\n+#include <utility>\n+\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"backend.h\"\n+#include \"target.h\"\n+#include \"rtl.h\"\n+#include \"tree.h\"\n+#include \"regs.h\"\n+#include \"stringpool.h\"\n+#include \"attribs.h\"\n+#include \"gimple.h\"\n+#include \"df.h\"\n+#include \"memmodel.h\"\n+#include \"tm_p.h\"\n+#include \"stringpool.h\"\n+#include \"optabs.h\"\n+#include \"emit-rtl.h\"\n+#include \"recog.h\"\n+#include \"diagnostic-core.h\"\n+#include \"output.h\"\n+#include \"fold-const.h\"\n+#include \"stor-layout.h\"\n+#include \"varasm.h\"\n+#include \"calls.h\"\n+#include \"explow.h\"\n+#include \"expr.h\"\n+#include \"langhooks.h\"\n+#include \"cfgrtl.h\"\n+#include \"gimplify.h\"\n+#include \"reload.h\"\n+#include \"builtins.h\"\n+#include \"tree-pass.h\"\n+\n+void wasm_print_operand (FILE *stream, rtx value, int mode);\n+\n+extern hash_map<const_rtx, tree> external_libcalls;\n+\n+namespace\n+{\n+\n+int indent;\n+void output_indent(FILE *stream)\n+{\n+ fprintf (stream, \"%*s\", indent * 2, \"\");\n+}\n+void output_indent()\n+{\n+ output_indent (asm_out_file);\n+}\n+\n+char *fake_out_file_data;\n+size_t fake_out_file_length;\n+FILE *saved_asm_out_file;\n+\n+hash_map<tree, std::pair<tree, const_tree>> import_map;\n+hash_set<const_rtx> external_libcall_set;\n+\n+bool\n+global_p (rtx reg)\n+{\n+ if (GET_CODE (reg) == SUBREG)\n+ reg = SUBREG_REG (reg);\n+ gcc_assert (GET_CODE (reg) == REG);\n+ return REGNO (reg) == STACK_POINTER_REGNUM;\n+}\n+\n+bool\n+is_escape (char x)\n+{\n+ const char *escapes = \"\\\"\\'\\\\\\t\\n\\r\";\n+ while (*escapes and x != *escapes)\n+ ++escapes;\n+ return *escapes;\n+}\n+\n+void\n+assemble_string (FILE *stream, const char *string, int size, bool hex_only)\n+{\n+ fprintf (stream, \" \\\"\");\n+ for (int i = 0; i != size; ++i)\n+ {\n+ char c[] = {'\\\\', string[i], '\\0'};\n+ if (c[1] < 32 || c[1] > 127 || hex_only)\n+ fprintf (stream, \"\\\\%0.2hhx\", c[1]);\n+ else\n+ fprintf (stream, \"%s\", c + !is_escape(c[1]));\n+ }\n+ fprintf (stream, \"\\\"\");\n+}\n+\n+void\n+assemble_zeroes (FILE *stream, unsigned HOST_WIDE_INT size)\n+{\n+ fputs (\" \\\"\", stream);\n+ for (unsigned HOST_WIDE_INT i = 0; i != size; ++i)\n+ fputs (\"\\\\00\", stream);\n+ fputs (\"\\\"\", stream);\n+}\n+\n+void\n+assemble_const_int (FILE *stream, HOST_WIDE_INT value, unsigned size)\n+{\n+ char val[sizeof (HOST_WIDE_INT)];\n+ for (int i = 0; i != sizeof (HOST_WIDE_INT); ++i)\n+ val[i] = value >> (i * 8);\n+ assemble_string (stream, val, size, true);\n+}\n+\n+/* Can handle following shapes:\n+ (const_int x)\n+ (symbol_ref x)\n+ (const (plus (symbol_ref x) (const_int y))\n+ (const (minus (symbol_ref x) (const_int y))\n+ (const (plus (const_int x) (const_int y))\n+ (const (minus (const_int x) (const_int y)) */\n+bool\n+assemble_integer (FILE *stream, rtx x, unsigned size, int)\n+{\n+ HOST_WIDE_INT addend = 0;\n+\n+ if (GET_CODE (x) == CONST)\n+ {\n+ x = XEXP (x, 0);\n+ switch (GET_CODE (x))\n+ {\n+ default:\n+ return false;\n+ case PLUS:\n+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)\n+ return false;\n+ addend = INTVAL (XEXP (x, 1));\n+ x = XEXP (x, 0);\n+ break;\n+ case MINUS:\n+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)\n+ return false;\n+ addend = -INTVAL (XEXP (x, 1));\n+ x = XEXP (x, 0);\n+ break;\n+ }\n+ }\n+ switch (GET_CODE (x))\n+ {\n+ default:\n+ return false;\n+ case CONST_INT:\n+ assemble_const_int (stream, INTVAL (x) + addend, size);\n+ return true;\n+ case SYMBOL_REF:\n+ tree decl = SYMBOL_REF_DECL (x);\n+ bool func_p = TREE_CODE (decl) == FUNCTION_DECL;\n+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));\n+\n+ assemble_zeroes (stream, size);\n+ fprintf (stream, \" (@reloc i%d %s \", size * 8,\n+ func_p ? \"functable\" : \"data\");\n+ wasm_print_operand (stream, x, 'l');\n+ if (addend)\n+ fprintf(stream, \" %+ld\", addend);\n+ fprintf (stream, \")\");\n+ return true;\n+ }\n+}\n+\n+\n+void\n+print_type (FILE *stream, const_tree type, bool first = false)\n+{\n+ const char *delim = first ? \"\" : \" \";\n+ switch (TREE_CODE (type))\n+ {\n+ default:\n+ gcc_unreachable ();\n+ case VOID_TYPE:\n+ break;\n+ case NULLPTR_TYPE:\n+ case VECTOR_TYPE:\n+ case COMPLEX_TYPE:\n+ print_type (stream, ptr_type_node, first);\n+ break;\n+ case UNION_TYPE:\n+ case RECORD_TYPE:\n+ if (TYPE_EMPTY_P (type))\n+ break;\n+ if (TYPE_TRANSPARENT_AGGR (type))\n+ print_type (stream, TREE_TYPE (first_field (type)), first);\n+ else\n+ print_type (stream, ptr_type_node, first);\n+ break;\n+ case POINTER_TYPE:\n+ case REFERENCE_TYPE:\n+ case OFFSET_TYPE:\n+ case INTEGER_TYPE:\n+ case BOOLEAN_TYPE:\n+ case ENUMERAL_TYPE:\n+ fprintf (stream, \"%s%s\", delim,\n+ TYPE_PRECISION (type) > 32 ? \"i64\" : \"i32\");\n+ break;\n+ case REAL_TYPE:\n+ fprintf (stream, \"%s%s\", delim,\n+ TYPE_PRECISION (type) > 32 ? \"f64\" : \"f32\");\n+ break;\n+ case FUNCTION_TYPE:\n+ case METHOD_TYPE:\n+ function_args_iterator it;\n+ tree *arg;\n+ fprintf (stream, \"%s(param\", delim);\n+ CUMULATIVE_ARGS args;\n+ INIT_CUMULATIVE_ARGS(args, type, nullptr, false, 0);\n+ FOREACH_FUNCTION_ARGS_PTR (type, arg, it)\n+ {\n+ function_arg_info info (*arg, stdarg_p (type));\n+ if (pass_by_reference(&args, info))\n+ print_type (stream, intSI_type_node);\n+ else\n+ print_type (stream, *arg);\n+ }\n+ fprintf (stream, \")\");\n+ tree return_type = TREE_TYPE (type);\n+ fprintf (stream, \" (result\");\n+ if (return_type != void_type_node)\n+ {\n+ print_type (stream, return_type);\n+ }\n+ fprintf (stream, \")\");\n+ break;\n+ }\n+}\n+void\n+print_local_decl (FILE *stream, rtx reg, bool param = false)\n+{\n+ output_indent (stream);\n+ fprintf (stream, \"(%s \", param ? \"param\" : \"local\");\n+ wasm_print_operand (stream, reg, 0);\n+ tree param_type = lang_hooks.types.type_for_mode (GET_MODE (reg), 0);\n+ print_type (stream, param_type);\n+ fprintf (stream, \")\\n\");\n+}\n+\n+void assemble_visibility (FILE *stream, const_tree decl)\n+{\n+ if (decl && DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN)\n+ fprintf (stream, \" hidden\");\n+}\n+\n+void assemble_binding (FILE *stream, const_tree decl)\n+{\n+ if (!decl)\n+ return;\n+ if (DECL_WEAK (decl))\n+ fprintf (stream, \" weak\");\n+ if (!TREE_PUBLIC (decl))\n+ fprintf (stream, \" local\");\n+}\n+\n+void assemble_init_prio (FILE *stream, const_tree decl)\n+{\n+ if (DECL_STATIC_CONSTRUCTOR (decl))\n+ {\n+ int prio = decl_init_priority_lookup (const_cast<tree> (decl));\n+ fprintf (stream, \" (init_prio %d)\", prio);\n+ }\n+}\n+\n+void assemble_sym_name (FILE *stream, const char *name)\n+{\n+ fprintf (stream, \" (name \\\"\");\n+ assemble_name (stream, name);\n+ fprintf (stream, \"\\\")\");\n+}\n+\n+\n+void\n+assemble_data_import (FILE *stream, const_tree decl, const char *name)\n+{\n+ output_indent (stream);\n+ fprintf (stream, \"(@sym.import.data $\");\n+ assemble_name (stream, name);\n+ assemble_binding (stream, decl);\n+ assemble_visibility (stream, decl);\n+ assemble_sym_name (stream, name);\n+ fprintf (stream, \")\\n\");\n+}\n+\n+/* Given the type, guess where assign_params must've put it */\n+void print_func_frame_related (FILE *stream, tree type)\n+{\n+ if (VOID_TYPE_P (type))\n+ return;\n+ if (TREE_CODE (type) == COMPLEX_TYPE\n+\t && targetm.calls.split_complex_arg (type))\n+ {\n+ print_func_frame_related (stream, TREE_TYPE (type));\n+ print_func_frame_related (stream, TREE_TYPE (type));\n+ return;\n+ }\n+ if (RECORD_OR_UNION_TYPE_P (type)\n+ && TYPE_TRANSPARENT_AGGR (type))\n+ type = TREE_TYPE (first_field (type));\n+\n+ function_arg_info arg (type, true);\n+ if (pass_by_reference (NULL, arg))\n+ print_type (stream, build_pointer_type (type));\n+ else\n+ print_type (stream, type);\n+}\n+\n+void\n+print_func_type (FILE *stream, const_tree type, bool for_block = false)\n+{\n+ tree result = TREE_TYPE (type);\n+\n+ /* Taken from assign_parms_augmented_arg_list, please keep in sync */\n+ bool return_by_ref = aggregate_value_p (result, type);\n+ if (!for_block)\n+ {\n+ fprintf (stream, \" (param\");\n+ if (return_by_ref)\n+ print_func_frame_related (stream, build_pointer_type (result));\n+ tree arg;\n+ function_args_iterator it;\n+ FOREACH_FUNCTION_ARGS (type, arg, it)\n+ {\n+ print_func_frame_related (stream, arg);\n+ }\n+ if (stdarg_p (type) || !TYPE_ARG_TYPES (type))\n+ print_func_frame_related (stream, ptr_type_node);\n+ fprintf (stream, \")\");\n+ }\n+\n+ fprintf (stream, \"%s(result\", for_block ? \"\": \" \");\n+ if (!return_by_ref)\n+ print_func_frame_related (stream, result);\n+ fprintf (stream, \")\");\n+}\n+\n+void print_global_type (FILE *stream, const_tree type)\n+{\n+ if (!TYPE_READONLY (type))\n+ fprintf (stream, \" (mut\");\n+ print_type (stream, type);\n+ if (!TYPE_READONLY (type))\n+ fprintf (stream, \")\");\n+}\n+\n+void\n+assemble_entity_import (FILE *stream, const char *name, const char *abi_name,\n+ const_tree decl)\n+{\n+ const_tree type = DECL_P (decl) ? TREE_TYPE (decl) : decl;\n+\n+ output_indent (stream);\n+ fprintf (stream, \"(import \\\"env\\\" \\\"\");\n+ assemble_name (stream, abi_name);\n+ fprintf (stream, \"\\\" \" );\n+ switch (TREE_CODE (type))\n+ {\n+ case INTEGER_TYPE:\n+ case BOOLEAN_TYPE:\n+ case ENUMERAL_TYPE:\n+ case POINTER_TYPE:\n+ case OFFSET_TYPE:\n+ case RECORD_TYPE:\n+ case UNION_TYPE: {\n+ fprintf (stream, \"(global $\");\n+ assemble_name (stream, name);\n+ print_global_type (stream, type);\n+ break;\n+ }\n+ case FUNCTION_TYPE:\n+ case METHOD_TYPE: {\n+ fprintf (stream, \"(func $\");\n+ assemble_name (stream, name);\n+ fprintf (stream, \" (@sym\");\n+ if (type != decl) {\n+ assemble_init_prio (stream, decl);\n+ assemble_binding (stream, decl);\n+ assemble_visibility (stream, decl);\n+ }\n+ fprintf (stream, \")\");\n+\n+ print_func_type (stream, type);\n+ break;\n+ }\n+ default:\n+ gcc_unreachable ();\n+ }\n+ fprintf (stream, \"))\\n\");\n+}\n+\n+void\n+decl_end (FILE *stream)\n+{\n+ fprintf (stream, \")\\n\");\n+}\n+\n+void\n+assemble_import (FILE *stream, const char *name, const_tree decl)\n+{\n+ if (!FUNC_OR_METHOD_TYPE_P (TREE_TYPE (decl)))\n+ return assemble_data_import (stream, decl, name);\n+ assemble_entity_import (stream, name, name, decl);\n+}\n+\n+template<class T>\n+void\n+print_nan_payload (FILE *stream, const REAL_VALUE_TYPE *n)\n+{\n+ constexpr int ndata = sizeof (T) / 4;\n+ long data[ndata];\n+ real_to_target (data, n, float_mode_for_size (sizeof (T) * 8).require ());\n+ int mantissa = std::numeric_limits<T>::digits - 1;\n+ int mantissa_words = ((mantissa - 1) / 32) + 1;\n+ for (int i = mantissa_words; i != ndata; ++i)\n+ data[i] = 0;\n+ unsigned mask = (1 << (mantissa % 32)) - 1;\n+ data[mantissa / 32] &= mask;\n+\n+ bool start = true;\n+ for (int i = ndata; i--;)\n+ if (start && !data[i])\n+ ;\n+ else if (start)\n+ fprintf (stream, \"%lx\", data[i]), start = false;\n+ else\n+ fprintf (stream, \"%0.8lx\", data[i]);\n+}\n+\n+}\n+\n+// TARGET_ASM_INIT_SECTIONS\n+void\n+wasm_asm_init_sections ()\n+{\n+ text_section = get_unnamed_section (SECTION_CODE, [](const char *){}, \"T\");\n+ data_section = get_unnamed_section (SECTION_WRITE, [](const char *){}, \"D\");\n+}\n+\n+// TARGET_ASM_FILE_START\n+void\n+wasm_asm_file_start ()\n+{\n+ output_indent(asm_out_file);\n+ indent++;\n+ fprintf (asm_out_file, \"(module\\n\");\n+ saved_asm_out_file = asm_out_file;\n+ asm_out_file = open_memstream (&fake_out_file_data, &fake_out_file_length);\n+}\n+\n+// TARGET_ASM_FILE_END\n+void\n+wasm_asm_file_end ()\n+{\n+ /* ??? All wasm globals should become builtin decls */\n+ output_indent (saved_asm_out_file);\n+ fprintf (saved_asm_out_file, \"(import \\\"env\\\" \\\"__stack_pointer\\\"\"\n+ \" (global $stack (mut i32)))\\n\");\n+\n+ output_indent (saved_asm_out_file);\n+ fprintf (saved_asm_out_file, \"(import \\\"env\\\" \\\"memory\\\" (memory 0))\\n\");\n+ output_indent (saved_asm_out_file);\n+ fprintf (saved_asm_out_file, \"(import \\\"env\\\" \\\"__indirect_function_table\\\" (table 0 funcref))\\n\");\n+\n+ for (auto [key, value]: import_map)\n+ {\n+ auto [name, decl] = value;\n+ assemble_import (saved_asm_out_file, IDENTIFIER_POINTER (name), decl);\n+ }\n+ for (auto sym: external_libcall_set)\n+ assemble_entity_import (saved_asm_out_file, XSTR (sym, 0), XSTR (sym, 0),\n+ *external_libcalls.get (sym));\n+\n+ fflush (asm_out_file);\n+ fwrite (fake_out_file_data, 1, fake_out_file_length, saved_asm_out_file);\n+\n+ fprintf (saved_asm_out_file, \")\\n\");\n+}\n+\n+// ASM_OUTPUT_FUNCTION_LABEL\n+void\n+wasm_asm_start_function (FILE *stream, tree decl, const char *name)\n+{\n+ output_indent(stream);\n+ indent++;\n+ fprintf (stream, \"(func $\");\n+ assemble_name (stream, name);\n+\n+ bool override_args = false;\n+ if (MAIN_NAME_P (DECL_NAME (decl)))\n+ {\n+ if (!cfun->machine->func_args)\n+ name = \"__main_void\";\n+ else\n+ name = \"__main_argc_argv\", override_args = true;\n+ }\n+\n+ fprintf (stream, \" (@sym\");\n+ if (TREE_CODE (decl) == FUNCTION_DECL)\n+ {\n+ assemble_init_prio (stream, decl);\n+ assemble_binding (stream, decl);\n+ assemble_visibility (stream, decl);\n+ assemble_sym_name (stream, name);\n+ }\n+ fprintf (stream, \") \");\n+\n+ tree type = TREE_TYPE (decl);\n+ //print_func_type (stream, type);\n+ fprintf (stream, \"\\n\");\n+ int i;\n+ rtx reg;\n+\n+ if (override_args)\n+ {\n+ FOR_EACH_VEC_SAFE_ELT (cfun->machine->func_args, i, reg)\n+ print_local_decl (stream, reg, i < 2);\n+ if (i < 1)\n+ {\n+ output_indent (stream);\n+ fprintf (stream, \"(param i32)\\n\");\n+ }\n+ if (i < 2)\n+ {\n+ output_indent (stream);\n+ fprintf (stream, \"(param i32)\\n\");\n+ }\n+ }\n+ else\n+ {\n+ FOR_EACH_VEC_SAFE_ELT (cfun->machine->func_args, i, reg)\n+ print_local_decl (stream, reg, true);\n+ if (stdarg_p (type))\n+ print_local_decl (stream, regno_reg_rtx[ARG_POINTER_REGNUM], true);\n+ if (DECL_STATIC_CHAIN (decl))\n+ print_local_decl (stream, regno_reg_rtx[STATIC_CHAIN_REGNUM], true);\n+ }\n+ output_indent (stream);\n+ print_func_type (stream, type, true);\n+ fprintf (stream, \"\\n\");\n+\n+ output_indent (stream);\n+ fprintf (stream, \";; hard\\n\");\n+ if (cfun->machine->return_mode != VOIDmode)\n+ print_local_decl (stream, gen_rtx_REG (cfun->machine->return_mode,\n+ WASM_RETURN_REGNUM));\n+\n+ df_set_regs_ever_live(WASM_CONTROL_POINTER_REGNUM, true);\n+ for (int r = 0; r < FIRST_PSEUDO_REGISTER; r++)\n+ {\n+ if (r == WASM_RETURN_REGNUM)\n+ continue;\n+ if (r == ARG_POINTER_REGNUM)\n+ continue;\n+ if (r == STATIC_CHAIN_REGNUM && DECL_STATIC_CHAIN (decl))\n+ continue;\n+ reg = regno_reg_rtx[r];\n+ if (df_regs_ever_live_p (r))\n+ {\n+ if (!global_p (reg))\n+ print_local_decl (stream, reg);\n+ }\n+ }\n+\n+ output_indent (stream);\n+ fprintf (stream, \";; locals\\n\");\n+ int max = max_reg_num();\n+ for (int r = FIRST_PSEUDO_REGISTER; r < max; r++)\n+ {\n+ reg = regno_reg_rtx[r];\n+ if (!reg)\n+ continue;\n+ if (reg == const0_rtx)\n+ continue;\n+ if (vec_safe_contains (cfun->machine->func_args, reg))\n+ continue;\n+ if (!bitmap_bit_p (cfun->machine->regs_ever_live, r))\n+ continue;\n+ print_local_decl (stream, reg);\n+ }\n+ output_indent (stream);\n+ fprintf (stream, \"(local.set $control (i32.const 0))\\n\");\n+ output_indent (stream);\n+ fprintf (stream, \"(loop $control \");\n+ print_func_type (stream, type, true);\n+ fprintf (stream, \"\\n\");\n+ indent++;\n+ int len = cfun->machine->labelno_to_labels->elements ();\n+ for (i = len - 1; i >= 0; --i)\n+ {\n+ output_indent (stream);\n+ indent++;\n+ fprintf (stream, \"(block $%d\\n\", i);\n+ }\n+\n+ output_indent (stream);\n+\n+ fprintf (stream, \"(br_table\");\n+ for (i = 0; i < len; ++i)\n+ fprintf (stream, \" $%d\", i);\n+ fprintf (stream, \" (local.get $control))\\n\");\n+}\n+\n+// ASM_DECLARE_FUNCTION_SIZE\n+void\n+wasm_asm_end_function (FILE *stream, tree, const char *name)\n+{\n+ indent--;\n+ output_indent (stream);\n+ fprintf (stream, \") ;; loop $control\\n\");\n+ indent--;\n+ output_indent (stream);\n+ fprintf (stream, \") ;;%s\\n\",\n+ IDENTIFIER_POINTER (targetm.asm_out.mangle_assembler_name (name)));\n+}\n+\n+// TARGET_ASM_ASSEMBLE_UNDEFINED_DECL\n+void\n+wasm_handle_import (FILE *, const char *name, const_tree decl)\n+{\n+ auto has_proto = [] (const_tree ty)\n+ {\n+ if (TREE_CODE (ty) != FUNCTION_DECL)\n+ return true;\n+ ty = TREE_TYPE (ty);\n+ return TYPE_ARG_TYPES (ty) || TYPE_NO_NAMED_ARGS_STDARG_P (ty);\n+ };\n+ bool existed = false;\n+ tree key = targetm.asm_out.mangle_assembler_name (name);\n+ auto &slot = import_map.get_or_insert (key, &existed);\n+ if (!existed || (!has_proto (slot.second) && has_proto (decl)))\n+ slot = {get_identifier (name), decl};\n+}\n+\n+// TARGET_ASM_ASSEMBLE_EXTERNAL_LIBCALL\n+void\n+wasm_handle_libcall (rtx symbol)\n+{\n+ external_libcall_set.add (symbol);\n+}\n+\n+// TARGET_ASM_INTEGER\n+bool\n+wasm_assemble_integer (rtx x, unsigned size, int align)\n+{\n+ return assemble_integer (asm_out_file, x, size, align);\n+}\n+\n+// TARGET_ASM_END_DECL\n+void\n+wasm_assemble_decl_end ()\n+{\n+ return decl_end(asm_out_file);\n+}\n+\n+// ASM_OUTPUT_ASCII\n+void\n+wasm_assemble_ascii (FILE *stream, const char *data, int len)\n+{\n+ return assemble_string (stream, data, len, false);\n+}\n+\n+// ASM_OUTPUT_SKIP\n+void\n+wasm_assemble_skip (FILE *stream, unsigned HOST_WIDE_INT len)\n+{\n+ return assemble_zeroes (stream, len);\n+}\n+\n+// ASM_DECLARE_OBJECT_NAME\n+// ASM_DECLARE_CONSTANT_NAME\n+void\n+wasm_assemble_data_begin (FILE *stream, tree decl, const char *name,\n+ HOST_WIDE_INT size, HOST_WIDE_INT align, bool pub)\n+{\n+ if (!name)\n+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));\n+ if (!size)\n+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));\n+ output_indent(stream);\n+ /* ??? This is a crutch. We should know the alignment of the constant we're\n+ declaring, but ASM_DECLARE_CONSTANT_NAME doesn't supply it. Assume it's\n+ huge and move on for now. */\n+ align = align ? align : 1024;\n+ fprintf (stream, \"(data (@sym (align %ld)) (i32.const 0) (@sym $\", align);\n+ assemble_name (stream, name);\n+ if (decl)\n+ {\n+ assemble_binding (stream, decl);\n+ }\n+ else\n+ {\n+ if (!pub)\n+ fprintf (stream, \" local\");\n+ }\n+ assemble_visibility (stream, decl);\n+ assemble_sym_name (stream, name);\n+ fprintf (stream, \" (size %ld)\", size);\n+ fprintf (stream, \")\");\n+}\n+\n+// ASM_OUTPUT_ALIGNED_DECL_COMMON\n+// ASM_OUTPUT_ALIGNED_DECL_LOCAL\n+void\n+wasm_assemble_data_zeros (FILE *stream, tree decl, const char *name,\n+ HOST_WIDE_INT size, HOST_WIDE_INT align, bool pub)\n+{\n+ wasm_assemble_data_begin (stream, decl, name, size, align, pub);\n+ wasm_assemble_skip (stream, size);\n+ decl_end(stream);\n+}\n+\n+// TARGET_PRINT_OPERAND_PUNCT_VALID_P\n+bool\n+wasm_valid_punct_p (unsigned char code)\n+{\n+ return code == '#';\n+}\n+\n+// TARGET_PRINT_OPERAND\n+void\n+wasm_print_operand (FILE *stream, rtx value, int mode)\n+{\n+ if (value && GET_CODE (value) == UNSPEC_VOLATILE)\n+ return wasm_print_operand (stream, XVECEXP (value, 0, 0), mode);\n+\n+ if (mode == '#') /* print return */\n+ {\n+ if (TREE_TYPE (TREE_TYPE (cfun->decl)) != void_type_node)\n+ fprintf (stream, \" (local.get $return)\");\n+ }\n+ else if (mode == 'M') /* print local/global */\n+ if (global_p(value))\n+ fprintf (stream, \"global\");\n+ else\n+ fprintf (stream, \"local\");\n+ else if (mode == 'A') /* print an arglist */\n+ {\n+ gcc_assert (GET_CODE (value) == PARALLEL);\n+ int len = XVECLEN (value, 0);\n+ for (int i = 1; i < len; ++i)\n+ {\n+ rtx arg = XVECEXP (value, 0, i);\n+ gcc_assert (GET_CODE (arg) == USE);\n+ rtx reg = XEXP (arg, 0);\n+ gcc_assert (GET_CODE (reg) == REG);\n+ fprintf (stream, \" \");\n+ wasm_print_operand (stream, reg, 'i');\n+ }\n+ }\n+ else if (mode == 'T') /* print a type */\n+ {\n+ if (GET_CODE (value) == PARALLEL)\n+ {\n+ int len = XVECLEN (value, 0);\n+ for (int i = 1; i < len; ++i)\n+ {\n+ rtx arg = XVECEXP (value, 0, i);\n+ gcc_assert (GET_CODE (arg) == USE);\n+ rtx reg = XEXP (arg, 0);\n+ gcc_assert (GET_CODE (reg) == REG);\n+ wasm_print_operand (stream, reg, mode);\n+ }\n+ }\n+ else if (REG_P (value))\n+ print_type (stream, lang_hooks.types.type_for_mode (GET_MODE (value), 0));\n+ else\n+ gcc_unreachable();\n+ }\n+ else switch (GET_CODE (value))\n+ {\n+ case MEM:\n+ {\n+ rtx addr = XEXP (value, 0);\n+ if (GET_CODE (addr) == PLUS)\n+ {\n+ fprintf (stream, \"offset=%lu \", UINTVAL (XEXP (addr, 1)));\n+ addr = XEXP (addr, 0);\n+ }\n+\n+ wasm_print_operand (stream, addr, 'i');\n+ break;\n+ }\n+ case CONST:\n+ case SYMBOL_REF:\n+ {\n+ rtx op = GET_CODE (value) == CONST ? XEXP (value, 0) : value;\n+ rtx offset = NULL_RTX;\n+ if (GET_CODE (op) == PLUS)\n+ offset = XEXP (op, 1), op = XEXP (op, 0);\n+ tree decl = SYMBOL_REF_P (op) ? SYMBOL_REF_DECL (op) : NULL_TREE;\n+ bool fndecl_p = decl && TREE_CODE (decl) == FUNCTION_DECL;\n+ if (mode == 'i')\n+ fprintf (stream, \"(i32.const 0 (@reloc %s \",\n+ fndecl_p ? \"functable\" : \"data\");\n+\n+ fprintf (stream, \"$\");\n+ output_addr_const (stream, op);\n+ if (offset)\n+ {\n+ fprintf (stream, \" %+\" HOST_WIDE_INT_PRINT \"d\",\n+ INTVAL (offset));\n+ }\n+ if (mode == 'i')\n+ fprintf (stream, \"))\");\n+ break;\n+ }\n+ case SUBREG:\n+ gcc_assert (SUBREG_BYTE (value) == 0);\n+ wasm_print_operand (stream, SUBREG_REG (value), mode);\n+ break;\n+ case REG:\n+ {\n+ int reg = REGNO (value);\n+ if (mode == 'i' || mode == 'o')\n+ fprintf (stream, \"%s%s.%s \", mode == 'o' ? \"\" : \"(\",\n+ global_p (value) ? \"global\" : \"local\",\n+ mode == 'i' ? \"get\" : \"set\");\n+ if (reg < FIRST_PSEUDO_REGISTER)\n+ fprintf (stream, \"%s\", reg_names[reg]);\n+ else\n+ {\n+ reg -= FIRST_PSEUDO_REGISTER;\n+ fprintf (stream, \"$local_%d\", reg);\n+ }\n+ if (mode == 'i')\n+ fprintf (stream, \")\");\n+ break;\n+ }\n+ case CONST_INT:\n+ if (mode == 'i')\n+ fprintf (stream, \"(i32.const \");\n+ fprintf (stream, \"%ld\", INTVAL (value));\n+ if (mode == 'i')\n+ fprintf (stream, \")\");\n+ break;\n+ case CONST_DOUBLE:\n+ {\n+ if (mode == 'i')\n+ fprintf (stream, \"(f%d.const \", GET_MODE_PRECISION (GET_MODE (value)));\n+ const REAL_VALUE_TYPE *n = CONST_DOUBLE_REAL_VALUE (value);\n+ if (REAL_VALUE_ISINF (*n))\n+ fprintf (stream, \"%cinf\", REAL_VALUE_NEGATIVE (*n) ? '-' : '+');\n+ else if (REAL_VALUE_ISNAN (*n))\n+ {\n+ fprintf (stream, \"%cnan\", REAL_VALUE_NEGATIVE (*n) ? '-' : '+');\n+ if (!n->canonical)\n+ {\n+ fprintf (stream, \":0x\");\n+ switch (GET_MODE (value))\n+ {\n+ case DFmode:\n+ print_nan_payload<double> (stream, n);\n+ break;\n+ case SFmode:\n+ print_nan_payload<float> (stream, n);\n+ break;\n+ default:\n+ gcc_unreachable();\n+ }\n+ }\n+ }\n+ else\n+ {\n+ /* There are always 32 bits in each long, no matter the size of\n+ the hosts long. */\n+ long tmp[2];\n+ REAL_VALUE_TO_TARGET_DOUBLE (*n, tmp);\n+ int32_t tmp2[2] = {(int32_t)tmp[0], (int32_t)tmp[1]};\n+ double r;\n+ std::memcpy (&r, tmp2, sizeof r);\n+ fprintf (stream, \"%a\", r);\n+ }\n+ if (mode == 'i')\n+ fprintf (stream, \")\");\n+ break;\n+ }\n+ default:\n+ gcc_unreachable ();\n+ }\n+}\n+\n+static int get_cf_label (size_t no)\n+{\n+ rtx_insn **l = cfun->machine->labelno_to_labels->get (no);\n+ if (!l)\n+ return -1;\n+ int cf = *cfun->machine->labels_to_cfno->get (*l);\n+ gcc_assert (cf >= 0);\n+ return cf;\n+}\n+\n+void\n+wasm_generate_internal_label (char *buf, const char *pfx, size_t no)\n+{\n+ if (!strcmp (pfx, \"L\"))\n+ sprint_ul (buf, get_cf_label (no));\n+ else\n+ sprintf (buf, \"%s\" HOST_WIDE_INT_PRINT_DEC, pfx, no);\n+}\n+\n+void\n+wasm_output_internal_label (FILE *stream, const char *pfx, size_t no)\n+{\n+ if (!strcmp (pfx, \"L\"))\n+ {\n+ int l = get_cf_label (no);\n+ if (l >= 0)\n+ {\n+ indent--;\n+ output_indent (stream);\n+ fprintf (stream, \") ;; $%d\\n\", l);\n+ }\n+ }\n+ else if (!strcmp (pfx, \"LFB\"))\n+ /* Function begin */;\n+ else if (!strcmp (pfx, \"LFE\"))\n+ /* Function end */;\n+ else\n+ /* unknown */;\n+}\ndiff --git a/gcc/config/wasm/wasm-cg.cc b/gcc/config/wasm/wasm-cg.cc\nnew file mode 100644\nindex 00000000000..c8d7f6812d1\n--- /dev/null\n+++ b/gcc/config/wasm/wasm-cg.cc\n@@ -0,0 +1,621 @@\n+/* WebAssembly code generation utilities.\n+ Copyright (C) 2025-2025 Free Software Foundation, Inc.\n+ Contributed by feedable.\n+\n+ This file is part of GCC.\n+\n+ GCC is free software; you can redistribute it and/or modify\n+ it under the terms of the GNU General Public License as published by\n+ the Free Software Foundation; either version 3, or (at your option)\n+ any later version.\n+\n+ GCC is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ GNU General Public License for more details.\n+\n+ You should have received a copy of the GNU General Public License\n+ along with GCC; see the file COPYING3. If not see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#define IN_TARGET_CODE 1\n+\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"backend.h\"\n+#include \"target.h\"\n+#include \"rtl.h\"\n+#include \"tree.h\"\n+#include \"regs.h\"\n+#include \"stringpool.h\"\n+#include \"attribs.h\"\n+#include \"gimple.h\"\n+#include \"df.h\"\n+#include \"memmodel.h\"\n+#include \"tm_p.h\"\n+#include \"stringpool.h\"\n+#include \"optabs.h\"\n+#include \"emit-rtl.h\"\n+#include \"recog.h\"\n+#include \"diagnostic-core.h\"\n+#include \"output.h\"\n+#include \"fold-const.h\"\n+#include \"stor-layout.h\"\n+#include \"varasm.h\"\n+#include \"calls.h\"\n+#include \"explow.h\"\n+#include \"expr.h\"\n+#include \"langhooks.h\"\n+#include \"cfgrtl.h\"\n+#include \"gimplify.h\"\n+#include \"reload.h\"\n+#include \"builtins.h\"\n+#include \"tree-pass.h\"\n+#include \"cfghooks.h\"\n+\n+hash_map<const_rtx, tree> external_libcalls;\n+\n+namespace\n+{\n+\n+rtx\n+unify_mem (rtx mem)\n+{\n+ HOST_WIDE_INT offset = 0;\n+ machine_mode mode = GET_MODE (mem);\n+ if (SUBREG_P (mem) && MEM_P(SUBREG_REG (mem)))\n+ {\n+ offset += SUBREG_BYTE (mem);\n+ mem = SUBREG_REG (mem);\n+ }\n+ if (!MEM_P (mem))\n+ return mem;\n+ rtx addr = XEXP (mem, 0);\n+ if (GET_CODE (addr) == PLUS && CONST_INT_P (XEXP (addr, 1)))\n+ {\n+ rtx offset_rtx = XEXP (addr, 1);\n+ addr = XEXP (addr, 0);\n+ offset += INTVAL (offset_rtx);\n+ }\n+ addr = force_reg (Pmode, addr);\n+ addr = gen_rtx_PLUS (Pmode, addr, gen_rtx_CONST_INT (Pmode, offset));\n+ if (offset < 0)\n+ addr = gen_rtx_PLUS (Pmode, force_reg (Pmode, addr), const0_rtx);\n+ mem = copy_rtx (mem);\n+ XEXP (mem, 0) = addr;\n+ return mem;\n+}\n+\n+bool symref_p (rtx expr)\n+{\n+ if (GET_CODE(expr) == CONST)\n+ {\n+ expr = XEXP (expr, 0);\n+ if (GET_CODE (expr) == PLUS)\n+ expr = XEXP (expr, 0);\n+ }\n+ return GET_CODE (expr) == SYMBOL_REF;\n+}\n+\n+void\n+record_libcall (const_rtx sym, tree ret)\n+{\n+ auto_vec<tree> args;\n+ vec<rtx, va_gc> *args_rtx = cfun->machine->call->args;\n+ int cnt = vec_safe_length (args_rtx);\n+ args.safe_grow (cnt);\n+ for (int i = 0; i != cnt; ++i)\n+ args[i] = lang_hooks.types.type_for_mode (GET_MODE ((*args_rtx)[i]), false);\n+ tree ty = build_function_type_array (ret, cnt, args.address ());\n+ bool existed;\n+ tree &slot = external_libcalls.get_or_insert (sym, &existed);\n+ if (existed)\n+ gcc_assert (slot == ty);\n+ else\n+ slot = ty;\n+}\n+\n+}\n+\n+machine_mode\n+wasm_real_register_mode (rtx reg)\n+{\n+ if (SUBREG_P (reg))\n+ reg = SUBREG_REG (reg);\n+ if (!REG_P (reg))\n+ return VOIDmode;\n+ machine_mode m = GET_MODE (reg);\n+ PROMOTE_MODE (m, 0, NULL_TREE);\n+ return m;\n+}\n+\n+static bool\n+expand_const (rtx dest, rtx src, machine_mode mode)\n+{\n+ if (!const_int_operand (src, mode) && !const_double_operand (src, mode) &&\n+ GET_CODE (src) != LABEL_REF && !symref_p (src))\n+ return false;\n+ if (symref_p (src))\n+\n+ if (GET_CODE(src) == CONST)\n+ if (GET_CODE (XEXP (src, 0)) == PLUS)\n+ if (GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT)\n+ {\n+ tree symref_dcl = SYMBOL_REF_DECL (XEXP (XEXP (src, 0), 0));\n+ if (INTVAL (XEXP (XEXP (src, 0), 1)) <= 0)\n+ src = force_reg (Pmode, XEXP (src, 0));\n+ else if (symref_dcl && TREE_CODE (symref_dcl) == FUNCTION_DECL)\n+ src = force_reg (Pmode, XEXP (src, 0));\n+ }\n+\n+ emit_insn (gen_rtx_SET (dest, src));\n+ return true;\n+}\n+\n+bool\n+wasm_expand_mov (rtx dest, rtx src, machine_mode mode)\n+{\n+ temporary_volatile_ok g {1};\n+ dest = unify_mem (dest);\n+ src = unify_mem (src);\n+ if (register_operand (dest, mode) && immediate_operand (src, mode))\n+ return expand_const (dest, src, mode);\n+ gcc_assert (REG_P (dest) || MEM_P (dest) || SUBREG_P (dest));\n+ if (register_operand (dest, mode) && memory_operand (src, mode))\n+ {\n+ emit_insn (gen_rtx_SET (dest, src));\n+ return true;\n+ }\n+ if (!SUBREG_P (src))\n+ src = force_reg (mode, src);\n+ emit_insn (gen_rtx_SET (dest, src));\n+ return true;\n+}\n+\n+void\n+wasm_expand_conv (rtx dest, rtx src, rtx_code code, bool strict)\n+{\n+ if (code == TRUNCATE)\n+ code = LOAD_EXTEND_OP (VOIDmode);\n+\n+ auto real_reg = [](rtx reg)\n+ {\n+ if (!SUBREG_P (reg))\n+ return reg;\n+ gcc_assert (SUBREG_BYTE (reg) == 0);\n+ return SUBREG_REG (reg);\n+ };\n+ rtx r_src = real_reg (src), r_dest = real_reg (dest);\n+\n+ /* This is an intra-reg conversion */\n+ bool src_di_p = (GET_MODE (r_src) == DImode);\n+ bool dest_di_p = (GET_MODE (r_dest) == DImode);\n+ bool do_conv = src_di_p != dest_di_p;\n+ bool do_intra = (GET_MODE (src) != SImode && GET_MODE (src) != DImode) || (GET_MODE (src) != DImode && (dest_di_p && src_di_p));\n+ machine_mode mid_mode = src_di_p ? DImode : SImode;\n+\n+ rtx mid = do_conv\n+ ? do_intra\n+ ? gen_reg_rtx (mid_mode)\n+ : src\n+ : simplify_gen_subreg (mid_mode, dest, GET_MODE (r_dest), 0);\n+ if (do_intra)\n+ {\n+ if (GET_MODE_PRECISION (GET_MODE (src)) >= GET_MODE_PRECISION (GET_MODE (mid)))\n+ src = simplify_gen_subreg (mid_mode, src, GET_MODE (r_src), 0);\n+ rtx op = gen_rtx_fmt_e_stat (code, mid_mode, src);\n+ rtx_insn *i = emit_insn (gen_rtx_SET (mid, op));\n+ extract_insn (i);\n+ }\n+\n+ if (do_conv)\n+ {\n+ if (mid_mode == DImode)\n+ code = TRUNCATE;\n+ rtx op = gen_rtx_fmt_e_stat (code, GET_MODE (r_dest), mid);\n+ rtx_insn *i = emit_insn (gen_rtx_SET (r_dest, op));\n+ extract_insn (i);\n+ }\n+}\n+\n+void\n+wasm_expand_call(rtx retval, rtx fn, rtx aux)\n+{\n+ bool vararg_p = false;\n+ bool has_proto = true;\n+ bool is_fn = true;\n+ bool need_chain = false;\n+\n+ if (tree type = cfun->machine->call->type)\n+ {\n+ vararg_p = stdarg_p (type);\n+ has_proto = TYPE_ARG_TYPES (type) || vararg_p;\n+ }\n+\n+ if (GET_CODE (XEXP (fn, 0)) == SYMBOL_REF)\n+ if (tree decl = SYMBOL_REF_DECL (XEXP (fn, 0)))\n+ {\n+ if (TREE_CODE (decl) != FUNCTION_DECL)\n+ is_fn = false;\n+ else if (DECL_STATIC_CHAIN (decl))\n+ need_chain = true;\n+ }\n+\n+ /* Pretend unprototyped fn calls dynamic. That way we can assert the function\n+ type ourselves, and if they don't agree with whatever is actually supplied\n+ by the linker, ANSI C 3.3.2.2 says it's undefied anyway */\n+ if (!has_proto || !is_fn)\n+ {\n+ rtvec ops = gen_rtvec (1, force_reg (Pmode, XEXP (fn, 0)));\n+ XEXP (fn, 0) = gen_rtx_UNSPEC_VOLATILE (SImode, ops,\n+ UNSPECV_CALL_ADDRESS_BARRIER);\n+ }\n+\n+ rtx call = gen_rtx_CALL(VOIDmode, fn, aux);\n+ if (retval)\n+ call = gen_rtx_SET (retval, call);\n+\n+ auto *args_rtx = cfun->machine->call->args;\n+\n+ /* ??? This should be handled by the call machinery, not me! */\n+ if (vararg_p)\n+ {\n+ rtx stdarg_reg = gen_reg_rtx (SImode);\n+ /* Rely on args being pushed in reverse order, and on only varargs being\n+ pushed, so that the beginning of the vararg buffer is stack_pointer_rtx.\n+ This is a hack. */\n+ emit_move_insn (stdarg_reg, stack_pointer_rtx);\n+ vec_safe_insert (args_rtx, 0, stdarg_reg);\n+ }\n+ if (need_chain)\n+ {\n+ rtx chain_reg = gen_reg_rtx (SImode);\n+ emit_move_insn (chain_reg, regno_reg_rtx[STATIC_CHAIN_REGNUM]);\n+ vec_safe_insert (args_rtx, 0, chain_reg);\n+ }\n+\n+ int argc = vec_safe_length (args_rtx);\n+ rtx res = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (argc + 1));\n+ XVECEXP (res, 0, 0) = call;\n+ for (int i = 0; i < argc; ++i)\n+ XVECEXP (res, 0, argc - i) = gen_rtx_USE (VOIDmode, (*args_rtx)[i]);\n+ emit_call_insn (res);\n+}\n+\n+void\n+wasm_expand_prologue ()\n+{\n+ emit_move_insn (regno_reg_rtx[WASM_BASE_POINTER_REGNUM],\n+ stack_pointer_rtx);\n+ if (crtl->stack_realign_needed)\n+ {\n+ int align = ~(crtl->max_used_stack_slot_alignment / BITS_PER_UNIT - 1);\n+ rtx align_mask = gen_rtx_CONST_INT (SImode, align);\n+ rtx reg = gen_reg_rtx (SImode);\n+ emit_move_insn (reg, align_mask);\n+ emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));\n+ }\n+\n+ if (flag_stack_usage_info)\n+ current_function_static_stack_size = 0;\n+ if (poly_int64 stack_space = get_frame_size ())\n+ {\n+ HOST_WIDE_INT unit_boundary = STACK_BOUNDARY / BITS_PER_UNIT;\n+ poly_int64 aligned = aligned_upper_bound (stack_space, unit_boundary);\n+ rtx aligned_space_rtx = gen_int_mode (aligned, Pmode);\n+ emit_insn (gen_sub2_insn (stack_pointer_rtx, aligned_space_rtx));\n+ emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);\n+ if (flag_stack_usage_info)\n+ current_function_static_stack_size = aligned;\n+ }\n+ if (HOST_WIDE_INT stack_space = crtl->outgoing_args_size)\n+ {\n+ emit_insn (gen_sub2_insn (stack_pointer_rtx,\n+ gen_int_mode (stack_space, Pmode)));\n+ }\n+}\n+\n+void\n+wasm_expand_epilogue ()\n+{\n+ emit_move_insn (stack_pointer_rtx, regno_reg_rtx[WASM_BASE_POINTER_REGNUM]);\n+}\n+\n+void\n+wasm_expand_compare (machine_mode m, rtx res, rtx op)\n+{\n+ rtx *left_p = &XEXP (op, 0), *right_p = &XEXP (op, 1);\n+\n+ *left_p = force_reg (m, *left_p);\n+ *right_p = force_reg (m, *right_p);\n+\n+ rtx left = *left_p, right = *right_p;\n+\n+ switch (GET_CODE (op))\n+ {\n+ case ORDERED:\n+ {\n+ rtx eq = gen_reg_rtx (SImode), ne = gen_reg_rtx (SImode);\n+ wasm_expand_compare (m, eq, gen_rtx_LE (SImode, left, right));\n+ wasm_expand_compare (m, ne, gen_rtx_GE (SImode, left, right));\n+ emit_insn (gen_iorsi3 (res, eq, ne));\n+ break;\n+ }\n+ case LTGT:\n+ {\n+ rtx eq = gen_reg_rtx (SImode), ne = gen_reg_rtx (SImode);\n+ wasm_expand_compare (m, eq, gen_rtx_LT (SImode, left, right));\n+ wasm_expand_compare (m, ne, gen_rtx_GT (SImode, left, right));\n+ emit_insn (gen_iorsi3 (res, eq, ne));\n+ break;\n+ }\n+ case LTU:\n+ case GTU:\n+ case LEU:\n+ case GEU:\n+ case LT:\n+ case GT:\n+ case LE:\n+ case GE:\n+ case EQ:\n+ case NE:\n+ op = gen_rtx_fmt_ee (GET_CODE (op), SImode, left, right);\n+ emit_insn (gen_rtx_SET (res, op));\n+ break;\n+ case UNLT:\n+ case UNGT:\n+ case UNLE:\n+ case UNGE:\n+ case UNEQ:\n+ case UNORDERED:\n+ {\n+ rtx_code cond_code = reverse_condition_maybe_unordered (GET_CODE (op));\n+ rtx cond = gen_rtx_fmt_ee (cond_code, SImode, left, right);\n+ rtx mid = gen_reg_rtx (SImode);\n+ wasm_expand_compare (m, mid, cond);\n+ emit_insn (gen_xorsi3 (res, mid, gen_rtx_CONST_INT (SImode, STORE_FLAG_VALUE)));\n+ break;\n+ }\n+ default:\n+ gcc_unreachable ();\n+ }\n+}\n+\n+bool\n+wasm_regno_mode_ok (unsigned regno, machine_mode mode)\n+{\n+ if (COMPLEX_MODE_P (mode))\n+ return false;\n+ if (regno == WASM_CONTROL_POINTER_REGNUM)\n+ return mode == SImode;\n+ if (regno == ARG_POINTER_REGNUM\n+ || regno == STACK_POINTER_REGNUM\n+ || regno == FRAME_POINTER_REGNUM\n+ || regno == STATIC_CHAIN_REGNUM\n+ || regno == WASM_BASE_POINTER_REGNUM)\n+ return mode == Pmode;\n+ if (GET_MODE_CLASS (mode) == MODE_INT)\n+ return mode < TImode;\n+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)\n+ return mode == DFmode || mode == SFmode;\n+ return false;\n+}\n+\n+bool\n+wasm_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t)\n+{\n+ return QImode <= from && from <= SImode && QImode <= to && to <= SImode;\n+}\n+\n+// TARGET_LEGITIMATE_ADDRESS_P\n+bool\n+wasm_legitimate_address_p (machine_mode, rtx x, bool, code_helper)\n+{\n+ if (GET_CODE (x) == CONST)\n+ x = XEXP (x, 0);\n+ if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) &&\n+ INTVAL (XEXP (x, 1)) >= 0)\n+ x = XEXP (x, 0);\n+ switch (GET_CODE (x))\n+ {\n+ case SYMBOL_REF:\n+ case LABEL_REF:\n+ case CONST_INT:\n+ case REG:\n+ return true;\n+ default:\n+ return false;\n+ }\n+}\n+\n+// TARGET_MARK_ARG_REGNOS\n+void\n+wasm_mark_arg_regnos (bitmap regnos)\n+{\n+ for (rtx arg: cfun->machine->func_args)\n+ bitmap_set_bit (regnos, REGNO(arg));\n+}\n+\n+// TARGET_START_CALL_ARGS\n+void\n+wasm_start_call_args (cumulative_args_t args)\n+{\n+ cfun->machine->call = get_cumulative_args (args);\n+}\n+\n+// TARGET_CALL_ARGS\n+void\n+wasm_call_args (cumulative_args_t args, rtx arg, tree type)\n+{\n+ get_cumulative_args (args)->type = type;\n+ if (arg == pc_rtx)\n+ return;\n+\n+if (GET_CODE (arg) == PARALLEL)\n+ {\n+ rtvec elts = XVEC (arg, 0);\n+ for (int i = 0; i != GET_NUM_ELEM (elts); ++i)\n+ wasm_call_args (args, XEXP (RTVEC_ELT (elts, i), 0), type);\n+ return;\n+ }\n+ gcc_assert (REG_P (arg));\n+ vec_safe_push (get_cumulative_args (args)->args, arg);\n+}\n+\n+// TARGET_END_CALL_ARGS\n+void\n+wasm_end_call_args (cumulative_args_t)\n+{\n+ cfun->machine->call = NULL;\n+ cfun->machine->unproto_call_p = false;\n+}\n+\n+// TARGET_FUNCTION_ARG_ADVANCE\n+void\n+wasm_function_arg_advance (cumulative_args_t, const function_arg_info &)\n+{\n+}\n+\n+// TARGET_FUNCTION_ARG_BOUNDARY\n+unsigned int wasm_vararg_align (machine_mode mode, const_tree type)\n+{\n+ unsigned align = 0;\n+\n+ if (type)\n+ align = TYPE_ALIGN (type);\n+ if (align)\n+ return MIN (MAX (align, BITS_PER_UNIT), BIGGEST_ALIGNMENT);\n+ return get_mode_alignment (mode);\n+}\n+\n+// TARGET_FUNCTION_VALUE\n+rtx\n+wasm_function_value (const_tree type, const_tree ARG_UNUSED (func),\n+ bool outgoing)\n+{\n+ machine_mode mode = TYPE_MODE (type);\n+ if (!cfun)\n+ /* fake return regnum since none is actually available */\n+ return gen_rtx_REG (mode, WASM_RETURN_REGNUM);\n+ if (outgoing)\n+ {\n+ /* Where we actually put the actual return val */\n+ cfun->machine->return_mode = mode;\n+ return gen_rtx_REG (mode, WASM_RETURN_REGNUM);\n+ }\n+ if (!cfun->machine->call)\n+ /* fake return regnum again, not in a call */\n+ return gen_rtx_REG (mode, WASM_RETURN_REGNUM);\n+\n+ /* Put the retval in a fresh reg, its mode may be different from actual\n+ retval, and we can't have that */\n+ return gen_reg_rtx (mode);\n+}\n+\n+\n+// TARGET_FUNCTION_ARG\n+rtx\n+wasm_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)\n+{\n+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);\n+\n+ if (arg.end_marker_p ())\n+ return NULL_RTX;\n+\n+ if (!arg.named)\n+ return NULL_RTX;\n+\n+ if (arg.mode == TImode)\n+ {\n+ rtx const8_rtx = gen_rtx_CONST_INT (VOIDmode, 8);\n+ rtvec para = gen_rtvec(2,\n+ gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const0_rtx),\n+ gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const8_rtx));\n+ return gen_rtx_PARALLEL (TImode, para);\n+ }\n+ return gen_reg_rtx (arg.mode);\n+}\n+\n+// TARGET_FUNCTION_INCOMING_ARG\n+rtx\n+wasm_function_incoming_arg (cumulative_args_t cum_v,\n+ const function_arg_info &arg)\n+{\n+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);\n+\n+ auto maybe_push_arg = [cum](rtx arg)\n+ {\n+ if (cum->incoming)\n+ vec_safe_push (cum->args, arg);\n+ };\n+\n+ if (arg.end_marker_p ())\n+ {\n+ gcc_assert (!cfun->machine->func_args);\n+ if (cum->incoming)\n+ cfun->machine->func_args = cum->args;\n+ return gen_rtx_CONST_INT (SImode, 80);\n+ }\n+ if (!arg.named)\n+ return NULL_RTX;\n+\n+ /* Int128 is passed as 2xint64_t, in LE order */\n+ if (arg.mode == TImode)\n+ {\n+ rtx const8_rtx = gen_rtx_CONST_INT (VOIDmode, 8);\n+\n+ rtx lsb = gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const0_rtx);\n+ rtx msb = gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const8_rtx);\n+ maybe_push_arg (lsb);\n+ maybe_push_arg (msb);\n+ rtvec para = gen_rtvec(2, lsb, msb);\n+ return gen_rtx_PARALLEL (TImode, para);\n+ }\n+ rtx reg = gen_reg_rtx (arg.mode);\n+ maybe_push_arg (reg);\n+ return reg;\n+}\n+\n+// TARGET_LIBCALL_VALUE\n+rtx wasm_libcall_value (machine_mode m, const_rtx sym)\n+{\n+ tree rtype = lang_hooks.types.type_for_mode (m, false);\n+ if (cfun && cfun->machine->call)\n+ record_libcall (sym, rtype);\n+ return wasm_function_value (rtype, NULL_TREE, false);\n+}\n+\n+// TARGET_PASS_BY_REFERENCE\n+bool\n+wasm_pass_by_reference (cumulative_args_t, const function_arg_info &arg)\n+{\n+ if (arg.type)\n+ {\n+ if (TREE_CODE (arg.type) == COMPLEX_TYPE)\n+ return true;\n+ if (TREE_CODE (arg.type) == VECTOR_TYPE)\n+ return true;\n+ }\n+ if (COMPLEX_MODE_P (arg.mode))\n+ return true;\n+ if (VECTOR_MODE_P (arg.mode))\n+ return true;\n+ if (arg.aggregate_type_p ())\n+ return true;\n+ return false;\n+}\n+// TARGET_RETURN_IN_MEMORY\n+bool\n+wasm_return_in_memory (const_tree type, const_tree ARG_UNUSED (fntype))\n+{\n+ if (TREE_CODE (type) == COMPLEX_TYPE)\n+ return true;\n+ if (TREE_CODE (type) == VECTOR_TYPE)\n+ return true;\n+ if (VECTOR_MODE_P (TYPE_MODE (type)))\n+ return true;\n+ if (COMPLEX_MODE_P (TYPE_MODE (type)))\n+ return true;\n+ return false;\n+}\ndiff --git a/gcc/config/wasm/wasm-modes.def b/gcc/config/wasm/wasm-modes.def\nnew file mode 100644\nindex 00000000000..e69de29bb2d\ndiff --git a/gcc/config/wasm/wasm-passes.cc b/gcc/config/wasm/wasm-passes.cc\nnew file mode 100644\nindex 00000000000..fc28ef93030\n--- /dev/null\n+++ b/gcc/config/wasm/wasm-passes.cc\n@@ -0,0 +1,153 @@\n+/* WebAssembly passes for code generation.\n+Copyright (C) 2025-2025 Free Software Foundation, Inc.\n+ Contributed by feedable.\n+\n+ This file is part of GCC.\n+\n+ GCC is free software; you can redistribute it and/or modify\n+ it under the terms of the GNU General Public License as published by\n+ the Free Software Foundation; either version 3, or (at your option)\n+ any later version.\n+\n+ GCC is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ GNU General Public License for more details.\n+\n+ You should have received a copy of the GNU General Public License\n+ along with GCC; see the file COPYING3. If not see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"backend.h\"\n+#include \"target.h\"\n+#include \"rtl.h\"\n+#include \"tree.h\"\n+#include \"regs.h\"\n+#include \"stringpool.h\"\n+#include \"attribs.h\"\n+#include \"gimple.h\"\n+#include \"df.h\"\n+#include \"memmodel.h\"\n+#include \"tm_p.h\"\n+#include \"stringpool.h\"\n+#include \"optabs.h\"\n+#include \"emit-rtl.h\"\n+#include \"recog.h\"\n+#include \"diagnostic-core.h\"\n+#include \"output.h\"\n+#include \"fold-const.h\"\n+#include \"stor-layout.h\"\n+#include \"varasm.h\"\n+#include \"calls.h\"\n+#include \"explow.h\"\n+#include \"expr.h\"\n+#include \"langhooks.h\"\n+#include \"cfgrtl.h\"\n+#include \"gimplify.h\"\n+#include \"reload.h\"\n+#include \"builtins.h\"\n+#include \"tree-pass.h\"\n+#include \"cfghooks.h\"\n+\n+namespace {\n+\n+const pass_data pass_data_count_labels =\n+{\n+ RTL_PASS, /* type */\n+ \"count_labels\", /* name */\n+ OPTGROUP_NONE, /* optinfo_flags */\n+ TV_MACH_DEP, /* tv_id */\n+ 0, /* properties_required */\n+ 0, /* properties_provided */\n+ 0, /* properties_destroyed */\n+ 0, /* todo_flags_start */\n+ 0, /* todo_flags_finish */\n+};\n+\n+class pass_count_labels : public rtl_opt_pass\n+{\n+ static void put_label (function *fun, rtx_insn *l, int &idx)\n+ {\n+ gcc_assert (!fun->machine->labels_to_cfno->put (l, idx++));\n+ int n = CODE_LABEL_NUMBER (l);\n+ gcc_assert (!fun->machine->labelno_to_labels->put (n, l));\n+ }\n+ static void mark_live (bitmap regs)\n+ {\n+\n+ df_clear_flags (DF_LR_RUN_DCE);\n+ df_set_flags (DF_NO_INSN_RESCAN | DF_NO_HARD_REGS);\n+ df_live_add_problem ();\n+ df_live_set_all_dirty ();\n+ df_analyze ();\n+ //regstat_init_n_sets_and_refs ();\n+ for (int i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); ++i)\n+ if (DF_REG_DEF_COUNT (i) || DF_REG_USE_COUNT (i))\n+ bitmap_set_bit (regs, i);\n+ }\n+ static void inject_trap (function *fun, basic_block bb)\n+ {\n+ rtx_insn *insn = BB_END (bb);\n+ if (INSN_P (insn)\n+ && (recog_memoized (insn) == CODE_FOR_trap))\n+ return;\n+ if (!vec_safe_length (bb->succs))\n+ make_edge (bb, fun->cfg->x_exit_block_ptr, EDGE_FALLTHRU);\n+ edge_iterator ei;\n+ edge e;\n+ FOR_EACH_EDGE (e, ei, bb->succs)\n+ if (e->flags & EDGE_FALLTHRU && cfun->machine->return_mode != VOIDmode)\n+ if (e->dest == fun->cfg->x_exit_block_ptr)\n+ {\n+ basic_block new_bb = split_edge (e);\n+ emit_insn_after (gen_trap(), BB_END (new_bb));\n+ }\n+ }\n+ static rtx_insn *find_label (basic_block bb)\n+ {\n+ rtx_insn *insn;\n+ FOR_BB_INSNS (bb, insn)\n+ {\n+ if (LABEL_P (insn))\n+ return insn;\n+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)\n+ return insn;\n+ }\n+ return NULL;\n+ }\n+public:\n+ pass_count_labels(gcc::context *ctxt)\n+ : rtl_opt_pass(pass_data_count_labels, ctxt)\n+ {}\n+\n+ /* opt_pass methods: */\n+ unsigned int execute (function *fun) override\n+ {\n+ basic_block bb;\n+ FOR_EACH_BB_FN (bb, fun)\n+ inject_trap (fun, bb);\n+\n+ bb = fun->cfg->x_entry_block_ptr->next_bb;\n+ int i = 0;\n+ put_label (fun, block_label (bb), i);\n+ mark_live (fun->machine->regs_ever_live);\n+\n+ FOR_BB_BETWEEN (bb, bb->next_bb, fun->cfg->x_exit_block_ptr, next_bb)\n+ {\n+ if (rtx_insn *x = find_label (bb))\n+ put_label (fun, x, i);\n+ }\n+ return 0;\n+ }\n+\n+};\n+\n+} // anon namespace\n+\n+rtl_opt_pass *make_pass_count_labels (gcc::context *ctx)\n+{\n+ return new pass_count_labels (ctx);\n+}\ndiff --git a/gcc/config/wasm/wasm-passes.def b/gcc/config/wasm/wasm-passes.def\nnew file mode 100644\nindex 00000000000..7c69cad12f5\n--- /dev/null\n+++ b/gcc/config/wasm/wasm-passes.def\n@@ -0,0 +1,27 @@\n+/* Description of target passes for WebAssembly\n+ Copyright (C) 2025-2025 Free Software Foundation, Inc.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it under\n+the terms of the GNU General Public License as published by the Free\n+Software Foundation; either version 3, or (at your option) any later\n+version.\n+\n+GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+/*\n+ Macros that can be used in this file:\n+ INSERT_PASS_AFTER (PASS, INSTANCE, TGT_PASS)\n+ INSERT_PASS_BEFORE (PASS, INSTANCE, TGT_PASS)\n+ REPLACE_PASS (PASS, INSTANCE, TGT_PASS)\n+ */\n+\n+ INSERT_PASS_BEFORE (pass_free_cfg, 1, pass_count_labels);\n\\ No newline at end of file\ndiff --git a/gcc/config/wasm/wasm-protos.h b/gcc/config/wasm/wasm-protos.h\nnew file mode 100644\nindex 00000000000..9aa5f6c0fe5\n--- /dev/null\n+++ b/gcc/config/wasm/wasm-protos.h\n@@ -0,0 +1,12 @@\n+\n+#ifdef RTX_CODE\n+extern void wasm_expand_prologue ();\n+extern void wasm_expand_epilogue ();\n+extern void wasm_expand_call (rtx retval, rtx fn, rtx aux);\n+extern void wasm_emit_jump (rtx dest, rtx fn);\n+extern bool wasm_expand_mov (rtx dest, rtx src, machine_mode mode);\n+extern void wasm_expand_conv (rtx, rtx, rtx_code, bool = true);\n+extern void wasm_expand_compare (machine_mode m, rtx res, rtx cmp);\n+extern machine_mode wasm_real_register_mode (rtx reg);\n+rtl_opt_pass *make_pass_count_labels (gcc::context *ctx);\n+#endif\ndiff --git a/gcc/config/wasm/wasm.cc b/gcc/config/wasm/wasm.cc\nnew file mode 100644\nindex 00000000000..0a5e746d87c\n--- /dev/null\n+++ b/gcc/config/wasm/wasm.cc\n@@ -0,0 +1,128 @@\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"backend.h\"\n+#include \"target.h\"\n+#include \"rtl.h\"\n+#include \"tree.h\"\n+#include \"stringpool.h\"\n+#include \"attribs.h\"\n+#include \"df.h\"\n+#include \"memmodel.h\"\n+#include \"stringpool.h\"\n+#include \"optabs.h\"\n+#include \"emit-rtl.h\"\n+#include \"recog.h\"\n+#include \"diagnostic-core.h\"\n+#include \"output.h\"\n+#include \"varasm.h\"\n+#include \"calls.h\"\n+#include \"explow.h\"\n+#include \"expr.h\"\n+#include \"builtins.h\"\n+\n+#include \"target.h\"\n+#include \"common/common-target.h\"\n+\n+static machine_function *\n+wasm_init_machine_status (void)\n+{\n+ machine_function *p = ggc_cleared_alloc<machine_function> ();\n+ p->labels_to_cfno = hash_map<rtx_insn *, int>::create_ggc (31);\n+ p->labelno_to_labels = hash_map<cfl_hash, rtx_insn *>::create_ggc (31);\n+ p->regs_ever_live = BITMAP_GGC_ALLOC ();\n+ return p;\n+}\n+\n+#define TARGET_OPTION_OVERRIDE wasm_option_override\n+static void\n+wasm_option_override (void)\n+{\n+ init_machine_status = wasm_init_machine_status;\n+}\n+\n+void wasm_asm_init_sections ();\n+#define TARGET_ASM_INIT_SECTIONS wasm_asm_init_sections\n+bool wasm_assemble_integer (rtx x, unsigned size, int align);\n+#define TARGET_ASM_INTEGER wasm_assemble_integer\n+void wasm_assemble_decl_end ();\n+#define TARGET_ASM_DECL_END wasm_assemble_decl_end\n+void wasm_handle_import (FILE *stream, const char *name, const_tree decl);\n+#define TARGET_ASM_ASSEMBLE_UNDEFINED_DECL wasm_handle_import\n+void wasm_handle_libcall (rtx symbol);\n+#define TARGET_ASM_EXTERNAL_LIBCALL wasm_handle_libcall\n+void wasm_assemble_data_begin (FILE *stream, tree decl, const char *name,\n+ HOST_WIDE_INT size, HOST_WIDE_INT align,\n+ bool pub);\n+#define TARGET_ASM_DECLARE_CONSTANT_NAME \\\n+ [] (FILE *stream, const char *name, const_tree, HOST_WIDE_INT size) \\\n+ { return wasm_assemble_data_begin (stream, 0, name, size, 0, false); }\n+\n+#define TARGET_ASM_GLOBALIZE_LABEL [](FILE *, const char *) {}\n+#define TARGET_ASM_ASSEMBLE_VISIBILITY [](tree, int) {}\n+#define TARGET_ASM_CONSTRUCTOR [] (rtx, int) {}\n+#define TARGET_ASM_DESTRUCTOR [] (rtx, int) {}\n+#define TARGET_USE_LATE_PROLOGUE_EPILOGUE [] { return true; }\n+\n+#define TARGET_ASM_FILE_START wasm_asm_file_start\n+void wasm_asm_file_start ();\n+#define TARGET_ASM_FILE_END wasm_asm_file_end\n+void wasm_asm_file_end ();\n+\n+bool wasm_valid_punct_p (unsigned char code);\n+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P wasm_valid_punct_p\n+void wasm_print_operand (FILE *stream, rtx value, int mode);\n+#define TARGET_PRINT_OPERAND wasm_print_operand\n+void wasm_output_internal_label (FILE *stream, const char *pfx, size_t no);\n+#define TARGET_ASM_INTERNAL_LABEL wasm_output_internal_label\n+#define TARGET_HAVE_NAMED_SECTIONS false\n+\n+bool wasm_regno_mode_ok (unsigned regno, machine_mode mode);\n+#define TARGET_HARD_REGNO_MODE_OK wasm_regno_mode_ok\n+bool wasm_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t);\n+#define TARGET_CAN_CHANGE_MODE_CLASS wasm_can_change_mode_class\n+bool wasm_legitimate_address_p (machine_mode, rtx x, bool, code_helper);\n+#define TARGET_LEGITIMATE_ADDRESS_P wasm_legitimate_address_p\n+void wasm_mark_arg_regnos (bitmap regnos);\n+#define TARGET_MARK_ARG_REGNOS wasm_mark_arg_regnos\n+\n+void wasm_start_call_args (cumulative_args_t args);\n+#define TARGET_START_CALL_ARGS wasm_start_call_args\n+void wasm_call_args (cumulative_args_t args, rtx arg, tree fntype);\n+#define TARGET_CALL_ARGS wasm_call_args\n+void wasm_end_call_args (cumulative_args_t);\n+#define TARGET_END_CALL_ARGS wasm_end_call_args\n+bool wasm_pass_by_reference(cumulative_args_t, const function_arg_info &arg);\n+#define TARGET_PASS_BY_REFERENCE wasm_pass_by_reference\n+bool wasm_return_in_memory (const_tree type, const_tree fntype);\n+#define TARGET_RETURN_IN_MEMORY wasm_return_in_memory\n+#define TARGET_SPLIT_COMPLEX_ARG [] (auto ...) { return false; }\n+\n+\n+#define TARGET_SCALAR_MODE_SUPPORTED_P [](scalar_mode m) \\\n+ { return default_scalar_mode_supported_p(m) && m != TImode; }\n+\n+#define TARGET_EXCEPT_UNWIND_INFO [](auto...) { return UI_NONE; }\n+\n+#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false\n+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS hook_bool_void_false\n+#define TARGET_STRICT_ARGUMENT_NAMING [] (auto ...) { return true; }\n+unsigned int wasm_vararg_align (machine_mode mode, const_tree type);\n+#define TARGET_FUNCTION_ARG_BOUNDARY wasm_vararg_align\n+void wasm_function_arg_advance (cumulative_args_t, const function_arg_info &);\n+#define TARGET_FUNCTION_ARG_ADVANCE wasm_function_arg_advance\n+rtx wasm_function_value (const_tree type, const_tree ARG_UNUSED (func), bool);\n+#define TARGET_FUNCTION_VALUE wasm_function_value\n+rtx wasm_function_arg (cumulative_args_t cum_v, const function_arg_info &arg);\n+#define TARGET_FUNCTION_ARG wasm_function_arg\n+rtx wasm_function_incoming_arg (cumulative_args_t cum_v,\n+ const function_arg_info &arg);\n+#define TARGET_FUNCTION_INCOMING_ARG wasm_function_incoming_arg\n+rtx wasm_libcall_value (machine_mode, const_rtx);\n+#define TARGET_LIBCALL_VALUE wasm_libcall_value\n+\n+#include \"target-def.h\"\n+gcc_target targetm = TARGET_INITIALIZER;\n+\n+#include \"common/common-target-def.h\"\n+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;\ndiff --git a/gcc/config/wasm/wasm.h b/gcc/config/wasm/wasm.h\nnew file mode 100644\nindex 00000000000..8adfb8d3fe4\n--- /dev/null\n+++ b/gcc/config/wasm/wasm.h\n@@ -0,0 +1,307 @@\n+/* WebAssembly cpu description.\n+ Copyright (C) 1997-2025 Free Software Foundation, Inc.\n+ Contributed by feedable.\n+\n+ This file is part of GCC.\n+\n+ GCC is free software; you can redistribute it and/or modify\n+ it under the terms of the GNU General Public License as published by\n+ the Free Software Foundation; either version 3, or (at your option)\n+ any later version.\n+\n+ GCC is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ GNU General Public License for more details.\n+\n+ You should have received a copy of the GNU General Public License\n+ along with GCC; see the file COPYING3. If not see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#ifndef GCC_WASM_H\n+#define GCC_WASM_H\n+\n+#ifndef USED_FOR_TARGET\n+#include \"statistics.h\"\n+#include \"vec.h\"\n+#include \"hash-table.h\"\n+#include \"hash-map.h\"\n+#endif\n+\n+/* Debug */\n+#define PREFERRED_DEBUGGING_TYPE NO_DEBUG\n+/* End debug */\n+\n+#define CC1PLUS_SPEC \"-stdlib=libc++\"\n+#define ASM_SPEC \"-r --enable-annotations %{v:-v} %{Wa,*:%*}\"\n+#define STANDARD_STARTFILE_PREFIX_1 \"/lib/wasm32-wasi/\"\n+#define STARTFILE_SPEC \"%R\" STANDARD_STARTFILE_PREFIX_1 \"crt1%O%s\"\n+#define LIB_SPEC \"%{!shared:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}\"\n+#define LINK_SPEC \"%{!o:-o a.out}\"\n+//#define LIB_SPEC \"%{!shared: -lm -lc}\"\n+\n+/* Run-time target specifications. */\n+#define TARGET_CPU_CPP_BUILTINS() \\\n+ do\t\t\t\t\t \\\n+ {\t\t\t\t\t \\\n+ builtin_define_std (\"wasm32\");\t \\\n+ builtin_assert (\"machine=wasm32\"); \\\n+ builtin_assert (\"cpu=wasm32\");\t \\\n+ cpp_define (parse_in, \"__wasm32__\");\\\n+ cpp_define (parse_in, \"__wasi__\"); \\\n+ }\t\t\t\t\t \\\n+ while (0)\n+\n+/* End run-time target specifications. */\n+\n+/* Regs */\n+#define WASM_RETURN_REGNUM 0\n+#define STACK_POINTER_REGNUM 1\n+#define FRAME_POINTER_REGNUM 2\n+#define ARG_POINTER_REGNUM 3\n+#define STATIC_CHAIN_REGNUM 4\n+#define WASM_CONTROL_POINTER_REGNUM 5\n+#define WASM_BASE_POINTER_REGNUM 6\n+\n+/* If this isn't defined, loads form $args will be performed with nested\n+ functions */\n+#define FRAME_POINTER_CFA_OFFSET(FNDECL) ((void)(FNDECL), 0)\n+\n+/* ??? IRA is a bit silly with on targets that don't do register allocation,\n+ in that it still needs free hard regs to play with, give it some for now */\n+#define REGISTER_NAMES \\\n+ {\t\t \\\n+ \"$return\", \\\n+ \"$stack\", \\\n+ \"$frame\", \\\n+ \"$args\", \\\n+ \"$chain\", \\\n+ \"$control\", \\\n+ \"$base\", \\\n+ \"general0\", \\\n+ \"general1\", \\\n+ \"general2\", \\\n+ \"general3\", \\\n+ }\n+\n+#define TARGET_NO_REGISTER_ALLOCATION true\n+#define FIRST_PSEUDO_REGISTER 11\n+#define FIXED_REGISTERS\t { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }\n+#define CALL_USED_REGISTERS { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }\n+\n+enum reg_class { NO_REGS, ALL_REGS,\tLIM_REG_CLASSES };\n+#define REG_CLASS_NAMES { \"NO_REGS\", \"ALL_REGS\" }\n+#define REG_CLASS_CONTENTS { { 0x0000 }, { 0xFFFF } }\n+#define N_REG_CLASSES (int) LIM_REG_CLASSES\n+\n+#define GENERAL_REGS ALL_REGS\n+#define REGNO_REG_CLASS(R) ALL_REGS\n+#define BASE_REG_CLASS ALL_REGS\n+#define INDEX_REG_CLASS NO_REGS\n+\n+#define REGNO_OK_FOR_BASE_P(X) true\n+#define REGNO_OK_FOR_INDEX_P(X) false\n+\n+#define CLASS_MAX_NREGS(class, mode) 1\n+\n+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE)\t\t\\\n+ if ((MODE) == QImode || (MODE) == HImode)\t\t\\\n+ (MODE) = SImode;\t\t\t\t\t \\\n+/* End regs */\n+\n+/* Calling convention */\n+#define PARM_BOUNDARY 8\n+#define STACK_BOUNDARY 128\n+#define FUNCTION_BOUNDARY 16\n+#define BIGGEST_ALIGNMENT 128\n+#define STRICT_ALIGNMENT 0\n+\n+/* Copied from elf.h and other places. We'd otherwise use\n+ BIGGEST_ALIGNMENT and fail a number of testcases. */\n+#define MAX_OFILE_ALIGNMENT (32768 * 8)\n+\n+#define FRAME_GROWS_DOWNWARD 0\n+#define STACK_GROWS_DOWNWARD 1\n+\n+#ifndef USED_FOR_TARGET\n+#define CUMULATIVE_ARGS wasm_cumulative_args\n+struct wasm_cumulative_args {\n+ bool incoming;\n+ vec<rtx, va_gc> *args = NULL;\n+ tree type = NULL;\n+};\n+#endif\n+\n+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \\\n+ CUM = {false}\n+#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \\\n+ CUM = {true}\n+\n+#define FUNCTION_ARG_REGNO_P(r) 0\n+#define FUNCTION_VALUE_REGNO_P(r) 0\n+\n+#define ELIMINABLE_REGS\t \\\n+ {\t\t\t\t\t\t\t \\\n+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}\t\\\n+ }\n+\n+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) (OFFSET) = 0\n+\n+#define FIRST_PARM_OFFSET(FNDECL) 0\n+/* We only use the stack for varargs, let's abuse that to achieve the proper\n+ layout for the varargs buffer */\n+#define ACCUMULATE_OUTGOING_ARGS 1\n+\n+#define TRAMPOLINE_SIZE 64\n+#define TRAMPOLINE_ALIGNMENT 32\n+/* End calling convention */\n+\n+/* Costs */\n+#define NO_FUNCTION_CSE 1\n+#define SLOW_BYTE_ACCESS 0\n+#define BRANCH_COST(speed_p, predictable_p) 6\n+/* End costs */\n+\n+/* Data layout */\n+#define STORE_FLAG_VALUE 1\n+\n+#define BITS_BIG_ENDIAN 1\n+#define BYTES_BIG_ENDIAN 0\n+#define WORDS_BIG_ENDIAN 0\n+#define UNITS_PER_WORD 8\n+#define MIN_UNITS_PER_WORD 4\n+\n+#define Pmode SImode\n+#define FUNCTION_MODE SImode\n+#define CASE_VECTOR_MODE SImode\n+\n+#define POINTER_SIZE 32\n+#define INT_TYPE_SIZE 32\n+#define CHAR_TYPE_SIZE 8\n+#define SHORT_TYPE_SIZE 16\n+#define LONG_TYPE_SIZE 32\n+#define LONG_LONG_TYPE_SIZE 64\n+#define DEFAULT_SIGNED_CHAR 0\n+#define WCHAR_TYPE_SIZE 32\n+/* ??? Need to figure out why do we have to set this in order for TI to not\n+ appear */\n+#define MAX_FIXED_MODE_SIZE 64\n+\n+#define SIZE_TYPE \"long unsigned int\"\n+#define WCHAR_TYPE \"long int\"\n+#define PTRDIFF_TYPE \"long int\"\n+#define INTPTR_TYPE \"long int\"\n+#define UINTPTR_TYPE \"long unsigned int\"\n+\n+/* From bpf */\n+#define INT8_TYPE \"signed char\"\n+#define INT16_TYPE \"short int\"\n+#define INT32_TYPE \"int\"\n+#define INT64_TYPE \"long long int\"\n+#define UINT8_TYPE \"unsigned char\"\n+#define UINT16_TYPE \"short unsigned int\"\n+#define UINT32_TYPE \"unsigned int\"\n+#define UINT64_TYPE \"long long unsigned int\"\n+\n+#define INT_LEAST8_TYPE INT8_TYPE\n+#define INT_LEAST16_TYPE INT16_TYPE\n+#define INT_LEAST32_TYPE INT32_TYPE\n+#define INT_LEAST64_TYPE INT64_TYPE\n+#define UINT_LEAST8_TYPE UINT8_TYPE\n+#define UINT_LEAST16_TYPE UINT16_TYPE\n+#define UINT_LEAST32_TYPE UINT32_TYPE\n+#define UINT_LEAST64_TYPE UINT64_TYPE\n+\n+#define INT_FAST8_TYPE INT8_TYPE\n+#define INT_FAST16_TYPE INT16_TYPE\n+#define INT_FAST32_TYPE INT32_TYPE\n+#define INT_FAST64_TYPE INT64_TYPE\n+#define UINT_FAST8_TYPE UINT8_TYPE\n+#define UINT_FAST16_TYPE UINT16_TYPE\n+#define UINT_FAST32_TYPE UINT32_TYPE\n+#define UINT_FAST64_TYPE UINT64_TYPE\n+\n+#define MOVE_MAX 8\n+#define MAX_REGS_PER_ADDRESS 1\n+#define LEGITIMATE_PIC_OPERAND_P(X) 1\n+\n+\n+#define WORD_REGISTER_OPERATIONS 1\n+#define LOAD_EXTEND_OP(M) SIGN_EXTEND\n+/* End data layout */\n+\n+/* Asm */\n+#define ASM_COMMENT_START \";;\"\n+#define ASM_APP_ON \"\"\n+#define ASM_APP_OFF \"\"\n+\n+#define GLOBAL_ASM_OP \"\"\n+\n+#ifndef USED_FOR_TARGET\n+void wasm_generate_internal_label (char *buf, const char *pfx, size_t no);\n+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM)\\\n+ wasm_generate_internal_label (LABEL, PREFIX, NUM)\n+#define ASM_OUTPUT_LABEL(stream, name) \\\n+ gcc_unreachable()\n+ //fprintf (stream, \") ;;%s\\n\", name)\n+#define ASM_OUTPUT_ALIGN(...)\n+\n+void wasm_assemble_data_begin (FILE *stream, tree decl, const char *name,\n+ HOST_WIDE_INT size, HOST_WIDE_INT align,\n+ bool pub);\n+#define ASM_DECLARE_OBJECT_NAME(FILE, DECL, NAME) \\\n+ wasm_assemble_data_begin (FILE, NAME, DECL, 0, 0, true);\n+void wasm_assemble_data_zeros (FILE *stream, tree decl, const char *name,\n+ HOST_WIDE_INT size, HOST_WIDE_INT align,\n+ bool pub);\n+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \\\n+ wasm_assemble_data_zeros (FILE, DECL, NAME, SIZE, ALIGN, true);\n+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \\\n+ wasm_assemble_data_zeros (FILE, DECL, NAME, SIZE, ALIGN, 0);\n+\n+void wasm_asm_start_function (FILE *stream, tree decl, const char *name);\n+#define ASM_OUTPUT_FUNCTION_LABEL(stream, name, decl) \\\n+ wasm_asm_start_function(stream, decl, name)\n+void wasm_asm_end_function (FILE *stream, tree decl, const char *name);\n+#define ASM_DECLARE_FUNCTION_SIZE(stream, name, decl) \\\n+ wasm_asm_end_function(stream, decl, name)\n+\n+void wasm_handle_import (FILE *stream, const char *name, const_tree decl);\n+#define ASM_OUTPUT_EXTERNAL(stream, decl, name) \\\n+ wasm_handle_import (stream, name, decl)\n+\n+void wasm_assemble_skip (FILE *stream, unsigned HOST_WIDE_INT len);\n+#define ASM_OUTPUT_SKIP(...) wasm_assemble_skip (__VA_ARGS__)\n+void wasm_assemble_ascii (FILE *stream, const char *data, int len);\n+#define ASM_OUTPUT_ASCII(...) wasm_assemble_ascii (__VA_ARGS__)\n+#endif\n+\n+#define HAS_INIT_SECTION\n+#define SUPPORTS_INIT_PRIORITY 1\n+#define SUPPORTS_WEAK 1\n+/* End asm */\n+\n+\n+#define FUNCTION_PROFILER(file, labelno) \\\n+ sorry_at (input_location, \\\n+\t \"profiling is not yet implemented for this architecture\")\n+\n+#ifndef USED_FOR_TARGET\n+struct cfl_hash: int_hash<int, -1, -2> {};\n+\n+struct GTY(()) machine_function\n+{\n+ vec<rtx, va_gc> *func_args; /* Arg list for the current function. */\n+ machine_mode return_mode;\n+ bool stdarg_p;\n+\n+ wasm_cumulative_args *call;\n+ bool unproto_call_p;\n+ hash_map<rtx_insn *, int> *labels_to_cfno;\n+ hash_map<cfl_hash, rtx_insn *> *labelno_to_labels;\n+ bitmap regs_ever_live;\n+ hash_map<rtx, tree> *saved_libcalls;\n+};\n+#endif\n+\n+#endif /* GCC_WASM_H */\ndiff --git a/gcc/config/wasm/wasm.md b/gcc/config/wasm/wasm.md\nnew file mode 100644\nindex 00000000000..a5f32f4228d\n--- /dev/null\n+++ b/gcc/config/wasm/wasm.md\n@@ -0,0 +1,495 @@\n+(include \"attrs.md\")\n+\n+(define_insn \"nop\"\n+ [(const_int 0)]\n+ \"\"\n+ \"(nop)\"\n+ [])\n+\n+(define_predicate \"symbol_operand\"\n+ (match_code \"symbol_ref\"))\n+(define_predicate \"funcref_operand\"\n+ (match_code \"symbol_ref\")\n+ {\n+ gcc_assert (GET_CODE (op) == SYMBOL_REF);\n+ return !SYMBOL_REF_DECL (op) || TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL;\n+ })\n+(define_predicate \"varref_operand\"\n+ (match_code \"symbol_ref\")\n+ {\n+ gcc_assert (GET_CODE (op) == SYMBOL_REF);\n+ return TREE_CODE (SYMBOL_REF_DECL (op)) == VAR_DECL;\n+ })\n+(define_predicate \"subregister_for_si_operand\"\n+ (ior (match_code \"reg\") (match_code \"subreg\"))\n+ {\n+ rtx x = op;\n+ if (SUBREG_P (x))\n+ x = SUBREG_REG (x);\n+ if (!REG_P (x))\n+ return false;\n+ machine_mode m = GET_MODE (x);\n+ int sign = 0;\n+ PROMOTE_MODE (m, sign, NULL_TREE);\n+ return m == SImode;\n+ })\n+\n+(define_predicate \"subregister_for_di_operand\"\n+ (ior (match_code \"reg\") (match_code \"subreg\"))\n+ {\n+ rtx x = op;\n+ if (SUBREG_P (x))\n+ x = SUBREG_REG (x);\n+ if (!REG_P (x))\n+ return false;\n+ machine_mode m = GET_MODE (x);\n+ int sign = 0;\n+ PROMOTE_MODE (m, sign, NULL_TREE);\n+ return m == DImode;\n+ })\n+(define_predicate \"wasm_register_operand\"\n+ (match_operand 0 \"register_operand\")\n+ {\n+ machine_mode m = GET_MODE (op);\n+ PROMOTE_MODE (m, 0, NULL_RTX);\n+ if (mode == TImode)\n+ return false;\n+ return m == wasm_real_register_mode (op);\n+ })\n+(define_predicate \"wasm_call_register_operand\"\n+ (ior (match_operand 0 \"wasm_register_operand\")\n+ (match_test \"GET_CODE (op) == UNSPEC_VOLATILE && wasm_register_operand (XVECEXP (op, 0, 0), mode)\")))\n+(define_predicate \"wasm_subregister_operand\"\n+ (match_operand 0 \"register_operand\")\n+ {\n+ machine_mode m = wasm_real_register_mode (op);\n+ return mode != TImode;\n+ })\n+\n+(define_predicate \"immediate_or_register_operand\"\n+ (ior (match_operand 0 \"immediate_operand\")\n+ (match_operand 0 \"register_operand\")))\n+\n+(define_predicate \"wasm_offset_operand\"\n+ (match_operand 0 \"const_int_operand\")\n+ {\n+ return INTVAL (op) >= 0;\n+ })\n+\n+ (define_expand \"mov<mode>\"\n+ [(set (match_operand:QHSDISDF 0 \"nonimmediate_operand\" \"\")\n+\t(match_operand:QHSDISDF 1 \"general_operand\" \"\"))]\n+ \"\"\n+ {\n+ if (wasm_expand_mov (operands[0], operands[1], <QHSDISDF:MODE>mode))\n+ DONE;\n+ else FAIL;\n+ })\n+\n+(define_expand \"jump\"\n+ [(set (pc)\n+ (label_ref (match_operand 0 \"\" \"\")))]\n+ \"\"\n+{\n+})\n+\n+(define_predicate \"call_operation\"\n+ (match_code \"parallel\")\n+{\n+ int arg_end = XVECLEN (op, 0);\n+\n+ for (int i = 1; i < arg_end; i++)\n+ {\n+ rtx elt = XVECEXP (op, 0, i);\n+\n+ if (GET_CODE (elt) != USE || !REG_P (XEXP (elt, 0)))\n+ return false;\n+ }\n+ return true;\n+})\n+(define_insn \"speculation_barrier\" [(const_int 0)] \"\" \"\")\n+(define_expand \"prologue\"\n+ [(const_int 777)]\n+ \"\"\n+ {\n+ wasm_expand_prologue ();\n+ DONE;\n+ })\n+(define_expand \"epilogue\"\n+ [(const_int 777)]\n+ \"\"\n+ {\n+ wasm_expand_epilogue ();\n+ emit_jump_insn (gen_return ());\n+ DONE;\n+ })\n+\n+;; Calls\n+(define_expand \"call\"\n+ [(call (match_operand:SI 0 \"memory_operand\" \"m\")\n+ (match_operand:SI 1 \"\" \"\"))]\n+ \"\"\n+ {\n+ wasm_expand_call(NULL_RTX, operands[0], operands[1]);\n+ DONE;\n+ })\n+\n+(define_expand \"call_value\"\n+ [(set (match_operand 0 \"register_operand\" \"=r\")\n+ (call (match_operand:SI 1 \"memory_operand\" \"m\")\n+ (match_operand:SI 2 \"\" \"\")))]\n+ \"\"\n+ {\n+ wasm_expand_call(operands[0], operands[1], operands[2]);\n+ DONE;\n+ })\n+\n+(define_insn \"*call_internal_indirect\"\n+ [(match_parallel 2 \"call_operation\"\n+ [(call (mem:SI (match_operand:P 0 \"wasm_call_register_operand\"))\n+\t (match_operand 1))])]\n+ \"\"\n+ \"(call_indirect (param%T2) (result)%A2 (%M0.get %0))\")\n+\n+(define_insn \"*call_value_internal_indirect\"\n+ [(match_parallel 3 \"call_operation\"\n+ [(set (match_operand 0 \"wasm_register_operand\" \"\")\n+\t (call (mem:SI (match_operand:P 1 \"wasm_call_register_operand\"))\n+\t\t (match_operand 2)))])]\n+ \"\"\n+ \"(%M0.set %0 (call_indirect (param%T3) (result%T0)%A3 (%M1.get %1)))\")\n+\n+(define_insn \"*call_internal\"\n+ [(match_parallel 2 \"call_operation\"\n+ [(call (mem:SI (match_operand:P 0 \"funcref_operand\"))\n+\t (match_operand 1))])]\n+ \"\"\n+ \"(call %0%A2)\")\n+\n+(define_insn \"*call_value_internal\"\n+ [(match_parallel 3 \"call_operation\"\n+ [(set (match_operand 0 \"wasm_register_operand\" \"\")\n+\t (call (mem:SI (match_operand:P 1 \"funcref_operand\"))\n+\t\t (match_operand 2)))])]\n+ \"\"\n+ \"(%M0.set %0 (call %1%A3))\")\n+\n+;; Literals\n+(define_insn \"*local_const<mode>\"\n+ [(set (match_operand:QHSDI 0 \"register_operand\")\n+\t (match_operand:QHSDI 1 \"const_int_operand\" \"\"))]\n+ \"\"\n+ \"(%M0.set %0 (<QHSDI:promote_type>.const %1))\")\n+\n+(define_insn \"*local_const<mode>\"\n+ [(set (match_operand:F 0 \"register_operand\")\n+\t (match_operand:F 1 \"immediate_operand\" \"\"))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.const %1))\")\n+\n+;; Address taking\n+(define_insn \"*local_const_addr\"\n+ [(set (match_operand:SI 0 \"register_operand\")\n+\t (match_operand:SI 1 \"immediate_operand\"))]\n+ \"\"\n+ \"(%M0.set %0 %i1)\")\n+\n+;; Moves\n+(define_insn \"*local_move<mode>\"\n+ [(set (match_operand:QHSDISDF 0 \"wasm_subregister_operand\" \"\")\n+ (match_operand:QHSDISDF 1 \"wasm_subregister_operand\" \"\"))]\n+ \"wasm_real_register_mode (operands[0]) == wasm_real_register_mode (operands[1])\"\n+ \"(%M0.set %0 (%M1.get %1))\")\n+\n+(define_insn \"*local_move<mode>\"\n+ [(set (match_operand:QHSDI 0 \"subregister_for_di_operand\" \"\")\n+ (match_operand:QHSDI 1 \"subregister_for_si_operand\" \"\"))]\n+ \"\"\n+ \"(%M0.set %0 (i64.extend_i32_s (%M1.get %1)))\")\n+\n+(define_insn \"*local_move<mode>\"\n+ [(set (match_operand:QHSDI 0 \"subregister_for_si_operand\" \"\")\n+ (match_operand:QHSDI 1 \"subregister_for_di_operand\" \"\"))]\n+ \"\"\n+ \"(%M0.set %0 (i32.wrap_i64 (%M1.get %1)))\")\n+\n+;; Comparisons\n+(define_expand \"cstore<mode>4\"\n+ [(set (match_operand:SI 0 \"register_operand\" \"\")\n+ (match_operator 1 \"comparison_operator\"\n+\t\t [(match_operand:REGF 2 \"general_operand\" \"\")\n+\t\t\t(match_operand:REGF 3 \"general_operand\" \"\")]))]\n+ \"\"\n+ {\n+ wasm_expand_compare (<MODE>mode, operands[0], operands[1]);\n+ DONE;\n+ })\n+\n+(define_insn \"*test<code>_<mode>\"\n+ [(set (match_operand:SI 0 \"wasm_register_operand\")\n+ (frelop:SI (match_operand:F 1 \"wasm_register_operand\")\n+\t\t (match_operand:F 2 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<opnamef> (%M1.get %1) (%M2.get %2)))\")\n+\n+(define_insn \"*test<code>_<mode>\"\n+ [(set (match_operand:SI 0 \"wasm_register_operand\")\n+ (irelop:SI (match_operand:REG 1 \"wasm_register_operand\")\n+\t (match_operand:REG 2 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<opname> (%M1.get %1) (%M2.get %2)))\")\n+\n+;; Control flow\n+(define_insn \"return\" [(return)] \"\" \"(return%#)\")\n+(define_insn \"trap\" [(trap_if (const_int 1) (const_int 0))] \"\" \"(unreachable)\")\n+\n+(define_expand \"cbranch<mode>4\"\n+ [(set (pc)\n+\t(if_then_else (match_operator 0 \"comparison_operator\"\n+\t\t\t\t [(match_operand:REGF 1 \"general_operand\" \"\")\n+\t\t\t\t (match_operand:REGF 2 \"general_operand\" \"\")])\n+\t\t (label_ref (match_operand 3 \"\" \"\"))\n+\t\t (pc)))]\n+ \"\"\n+ {\n+ rtx cond = gen_reg_rtx (SImode);\n+ emit_insn (gen_cstore<mode>4 (cond, operands[0], operands[1], operands[2]));\n+ emit_jump_insn (gen_branch (operands[3], cond));\n+ DONE;\n+ })\n+\n+(define_insn \"branch\"\n+ [(set (pc)\n+\t(if_then_else (ne (match_operand:SI 1 \"wasm_register_operand\" \"\")\n+\t (const_int 0))\n+\t\t (label_ref (match_operand 0 \"\" \"\"))\n+\t\t (pc)))]\n+ \"\"\n+ \"(br_if $control (local.set $control (i32.const %l0)) (%M1.get %1))\")\n+\n+(define_insn \"*jump\"\n+ [(set (pc) (label_ref (match_operand 0 \"\" \"\")))]\n+ \"\"\n+ \"(br $control (local.set $control (i32.const %l0)))\")\n+\n+;; Int memops\n+(define_insn \"*store<mode>\"\n+ [(set (match_operand:REGF 0 \"memory_operand\")\n+ (match_operand:REGF 1 \"wasm_register_operand\"))]\n+ \"\"\n+ \"(<types>.store %m0 %i1)\")\n+\n+(define_insn \"*load<mode>\"\n+ [(set (match_operand:REGF 0 \"wasm_register_operand\")\n+ (match_operand:REGF 1 \"memory_operand\"))]\n+ \"\"\n+ \"(%o0 (<types>.load %m1))\")\n+\n+;; I64 subreg memops\n+(define_insn \"*store<SUBREGDI:mode>\"\n+ [(set (match_operand:SUBREGDI 0 \"memory_operand\")\n+ (match_operand:SUBREGDI 1 \"subregister_for_di_operand\"))]\n+ \"\"\n+ \"(i64.store<SUBREGDI:size> %m0 %i1)\")\n+\n+(define_insn \"*load<SUBREGDI:mode>\"\n+ [(set (match_operand:SUBREGDI 0 \"subregister_for_di_operand\")\n+ (match_operand:SUBREGDI 1 \"memory_operand\"))]\n+ \"\"\n+ \"(%o0 (i64.load<SUBREGSI:size>_s %m1))\")\n+\n+;; I32 subreg memops\n+(define_insn \"*store<SUBREGSI:mode>\"\n+ [(set (match_operand:SUBREGSI 0 \"memory_operand\" \"\")\n+ (match_operand:SUBREGSI 1 \"subregister_for_si_operand\" \"\"))]\n+ \"\"\n+ \"(i32.store<SUBREGSI:size> %m0 %i1)\")\n+\n+(define_insn \"*load<SUBREGSI:mode>\"\n+ [(set (match_operand:SUBREGSI 0 \"subregister_for_si_operand\")\n+ (match_operand:SUBREGSI 1 \"memory_operand\"))]\n+ \"\"\n+ \"(%o0 (i32.load<SUBREGSI:size>_s %i1))\")\n+\n+;; Binary integer\n+(define_expand \"<opname_rt><mode>3\"\n+ [(set (match_operand:REG 0 \"register_operand\" \"\")\n+\t(ibinop:REG (match_operand:REG 1 \"immediate_or_register_operand\" \"\")\n+ (match_operand:REG 2 \"immediate_or_register_operand\" \"\")))]\n+ \"\"\n+ {\n+ if (!subregister_for_<REG:mode>_operand(operands[1], <REG:MODE>mode))\n+ operands[1] = force_reg (<REG:MODE>mode, operands[1]);\n+ if (!subregister_for_<REG:mode>_operand(operands[2], <REG:MODE>mode))\n+ operands[2] = force_reg (<REG:MODE>mode, operands[2]);\n+ })\n+\n+(define_insn \"*<opname_rt><mode>3\"\n+ [(set (match_operand:REG 0 \"wasm_register_operand\")\n+\t (ibinop:REG (match_operand:REG 1 \"wasm_register_operand\")\n+ (match_operand:REG 2 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<ibinop:opname> (%M1.get %1) (%M2.get %2)))\")\n+\n+;; Unary integer\n+(define_expand \"<opname_rt><mode>2\"\n+ [(set (match_operand:REG 0 \"register_operand\")\n+ \t(iunop:REG (match_operand:REG 1 \"immediate_or_register_operand\")))]\n+ \"\"\n+ {\n+ if (!subregister_for_<REG:mode>_operand(operands[1], <REG:MODE>mode))\n+ operands[1] = force_reg (<REG:MODE>mode, operands[1]);\n+ })\n+\n+(define_insn \"*<opname_rt><mode>2\"\n+ [(set (match_operand:REG 0 \"wasm_register_operand\")\n+\t (iunop:REG (match_operand:REG 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<iunop:opname> (%M1.get %1)))\")\n+\n+;; Binary float\n+(define_expand \"<opname_rt><mode>3\"\n+ [(set (match_operand:F 0 \"register_operand\")\n+\t (fbinop:F (match_operand:F 1 \"immediate_or_register_operand\")\n+ (match_operand:F 2 \"immediate_or_register_operand\")))]\n+ \"\"\n+ {\n+ operands[1] = force_reg (<MODE>mode, operands[1]);\n+ operands[2] = force_reg (<MODE>mode, operands[2]);\n+ })\n+\n+(define_insn \"*<opname_rt><mode>3\"\n+ [(set (match_operand:F 0 \"wasm_register_operand\")\n+\t (fbinop:F (match_operand:F 1 \"wasm_register_operand\")\n+ (match_operand:F 2 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<opnamef> (%M1.get %1) (%M2.get %2)))\")\n+\n+;; Unary float\n+(define_expand \"<opname_rt><mode>2\"\n+ [(set (match_operand:F 0 \"register_operand\")\n+ \t(funop:F (match_operand:F 1 \"immediate_or_register_operand\")))]\n+ \"\"\n+ {\n+ operands[1] = force_reg (<MODE>mode, operands[1]);\n+ })\n+\n+(define_insn \"*<opname_rt><mode>2\"\n+ [(set (match_operand:F 0 \"wasm_register_operand\")\n+\t (funop:F (match_operand:F 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<types>.<funop:opnamef> (%M1.get %1)))\")\n+\n+;; Integer conv\n+(define_expand \"<iconvop:opname_rt><QHSDI2:mode><QHSDI:mode>2\"\n+ [(set (match_operand:QHSDI 0 \"wasm_subregister_operand\")\n+ (iconvop:QHSDI (match_operand:QHSDI2 1 \"wasm_subregister_operand\")))]\n+ \"\"\n+ {\n+ wasm_expand_conv (operands[0], operands[1], <iconvop:CODE>, false);\n+ DONE;\n+ })\n+\n+(define_insn \"*extend_si_<SUBREGSI:mode><QHSDI:mode>\"\n+ [(set (match_operand:QHSDI 0 \"register_operand\")\n+ (sign_extend:QHSDI (match_operand:SUBREGSI 1 \"register_operand\")))]\n+ \"wasm_real_register_mode (operands[0]) == SImode && wasm_real_register_mode (operands[1]) == SImode\"\n+ \"(%M0.set %0 (i32.extend<SUBREGSI:size>_s (%M1.get %1)))\")\n+\n+(define_insn \"*extend_di_<SUBREGDI:mode><QHSDI:mode>\"\n+ [(set (match_operand:QHSDI 0 \"register_operand\")\n+ (sign_extend:QHSDI (match_operand:SUBREGDI 1 \"register_operand\")))]\n+ \"wasm_real_register_mode (operands[0]) == DImode && wasm_real_register_mode (operands[1]) == DImode\"\n+ \"(%M0.set %0 (i64.extend<SUBREGDI:size>_s (%M1.get %1)))\")\n+(define_insn \"*extend_sidi\"\n+ [(set (match_operand:DI 0 \"register_operand\")\n+ (sign_extend:DI (match_operand:SI 1 \"register_operand\")))]\n+ \"REG_P (operands[0]) && REG_P (operands[1])\"\n+ \"(%M0.set %0 (i64.extend_i32_s (%M1.get %1)))\")\n+(define_insn \"*uextend_sidi\"\n+ [(set (match_operand:DI 0 \"register_operand\")\n+ (zero_extend:DI (match_operand:SI 1 \"register_operand\")))]\n+ \"REG_P (operands[0]) && REG_P (operands[1])\"\n+ \"(%M0.set %0 (i64.extend_i32_u (%M1.get %1)))\")\n+(define_insn \"*truncate_disi\"\n+ [(set (match_operand:SI 0 \"register_operand\")\n+ (truncate:SI (match_operand:DI 1 \"register_operand\")))]\n+ \"REG_P (operands[0]) && REG_P (operands[1])\"\n+ \"(%M0.set %0 (i32.wrap_i64 (%M1.get %1)))\")\n+\n+;; Float conv\n+(define_insn \"extendsfdf2\"\n+ [(set (match_operand:DF 0 \"wasm_register_operand\")\n+ (float_extend:DF (match_operand:SF 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (f64.promote_f32 (%M1.get %1)))\")\n+\n+(define_insn \"truncdfsf2\"\n+ [(set (match_operand:SF 0 \"wasm_register_operand\")\n+ (float_truncate:SF (match_operand:DF 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (f32.demote_f64 (%M1.get %1)))\")\n+\n+;; Float -> int conv\n+(define_insn \"fix_trunc<F:mode><REG:mode>2\"\n+ [(set (match_operand:REG 0 \"wasm_register_operand\")\n+ (fix:REG (match_operand:F 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<REG:types>.trunc_sat_<F:types>_s (%M1.get %1)))\")\n+\n+(define_insn \"fixuns_trunc<F:mode><REG:mode>2\"\n+ [(set (match_operand:REG 0 \"wasm_register_operand\")\n+ (unsigned_fix:REG (match_operand:F 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<REG:types>.trunc_sat_<F:types>_u (%M1.get %1)))\")\n+\n+;; Int -> float conv\n+(define_insn \"float<REG:mode><F:mode>2\"\n+ [(set (match_operand:F 0 \"wasm_register_operand\")\n+ (float:F (match_operand:REG 1 \"wasm_register_operand\")))]\n+ \"\"\n+ \"(%M0.set %0 (<F:types>.convert_<REG:types>_s (%M1.get %1)))\")\n+\n+;; Rectify int <-> float cast\n+;;(define_insn \"floatuns<REG:mode><F:mode>2\"\n+;; [(set (match_operand:F 0 \"register_operand\")\n+;; (unsigned_float:F (match_operand:REG 1 \"register_operand\")))]\n+;; \"\"\n+;; \"(%M0.set %0 (<F:types>.convert_<REG:types>_u (%M1.get %1)))\")\n+;;\n+;;(define_subst \"swap_subreg_s_<mode>\"\n+;; [(set (match_operand:REGF 0)\n+;; (subreg:REGF (match_operand:<REGF:REG2F> 1) 0))]\n+;; \"\"\n+;; [(set (subreg:<REGF:REG2F> (match_dup 0) 0)\n+;; (match_dup 1))])\n+;;(define_subst_attr \"swap_subregsi\" \"swap_subreg_s_si\" \"_from\" \"_to\")\n+;;(define_subst_attr \"swap_subregdi\" \"swap_subreg_s_di\" \"_from\" \"_to\")\n+;;(define_subst_attr \"swap_subregsf\" \"swap_subreg_s_sf\" \"_from\" \"_to\")\n+;;(define_subst_attr \"swap_subregdf\" \"swap_subreg_s_df\" \"_from\" \"_to\")\n+\n+;; Float -> int cast\n+(define_insn \"*cast<REG:reg2f><REG:mode>\"\n+ [(set (match_operand:REG 0 \"wasm_register_operand\")\n+ (subreg:REG (match_operand:<REG:REG2F> 1 \"wasm_register_operand\") 0))]\n+ \"\"\n+ \"(%M0.set %0 (<REG:types>.reinterpret_<reg2f_types> (%M1.get %1)))\")\n+\n+(define_insn \"*cast<REG:reg2f><REG:mode>\"\n+ [(set (subreg:<REG:REG2F> (match_operand:REG 0 \"wasm_register_operand\") 0)\n+ (match_operand:<REG:REG2F> 1 \"wasm_register_operand\"))]\n+ \"\"\n+ \"(%M0.set %0 (<REG:types>.reinterpret_<reg2f_types> (%M1.get %1)))\")\n+\n+;; Int -> float cast\n+(define_insn \"*cast<mode><reg2f>\"\n+ [(set (match_operand:<REG2F> 0 \"wasm_register_operand\")\n+ (subreg:<REG2F> (match_operand:REG 1 \"wasm_register_operand\") 0))]\n+ \"\"\n+ \"(%M0.set %0 (<reg2f_types>.reinterpret_<REG:types> (%M1.get %1)))\")\n+\n+(define_insn \"*cast<mode><reg2f>\"\n+ [(set (subreg:REG (match_operand:<REG2F> 0 \"wasm_register_operand\") 0)\n+ (match_operand:REG 1 \"wasm_register_operand\"))]\n+ \"\"\n+ \"(%M0.set %0 (<reg2f_types>.reinterpret_<REG:types> (%M1.get %1)))\")\n\\ No newline at end of file\ndiff --git a/libgcc/config.host b/libgcc/config.host\nindex ac10ccc4340..61404f2a18d 100644\n--- a/libgcc/config.host\n+++ b/libgcc/config.host\n@@ -1574,6 +1574,11 @@ nvptx-*)\n \ttmake_file=\"$tmake_file nvptx/t-nvptx\"\n \textra_parts=\"crt0.o\"\n \t;;\n+wasm*-*-*)\n+\ttmake_file=\"$tmake_file wasm/t-wasm\"\n+\t# unwind_header=config/no-unwind.h\n+\t# extra_parts=\"crt0.o\"\n+\t;;\n *)\n \techo \"*** Configuration ${host} not supported\" 1>&2\n \texit 1\ndiff --git a/libgcc/config/wasm/t-wasm b/libgcc/config/wasm/t-wasm\nnew file mode 100644\nindex 00000000000..bd09d3c0dbf\n--- /dev/null\n+++ b/libgcc/config/wasm/t-wasm\n@@ -0,0 +1,4 @@\n+LIB2ADDEH=\n+\n+# Debug information is not yet supported\n+LIBGCC2_DEBUG_CFLAGS = -g0\n\\ No newline at end of file\n", "prefixes": [ "RFC", "2/3" ] }