{"id":2215432,"url":"http://patchwork.ozlabs.org/api/patches/2215432/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260324151840.3671675-1-philipp.tomsich@vrull.eu/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","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":"<20260324151840.3671675-1-philipp.tomsich@vrull.eu>","list_archive_url":null,"date":"2026-03-24T15:18:40","name":"[GCC17-stage1] RISC-V: Synthesize FP constants via integer instructions + fmv","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"34073fd20cd3dc3e031d2126997ea51d7952788b","submitter":{"id":80556,"url":"http://patchwork.ozlabs.org/api/people/80556/?format=json","name":"Philipp Tomsich","email":"philipp.tomsich@vrull.eu"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260324151840.3671675-1-philipp.tomsich@vrull.eu/mbox/","series":[{"id":497304,"url":"http://patchwork.ozlabs.org/api/series/497304/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=497304","date":"2026-03-24T15:18:40","name":"[GCC17-stage1] RISC-V: Synthesize FP constants via integer instructions + fmv","version":1,"mbox":"http://patchwork.ozlabs.org/series/497304/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2215432/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2215432/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=vrull.eu header.i=@vrull.eu header.a=rsa-sha256\n header.s=google header.b=Fychp7vW;\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=vrull.eu header.i=@vrull.eu header.a=rsa-sha256\n header.s=google header.b=Fychp7vW","sourceware.org;\n dmarc=none (p=none dis=none) header.from=vrull.eu","sourceware.org; spf=pass smtp.mailfrom=vrull.eu","server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.167.42"],"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 4fgDGc3j0kz1xy1\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 02:19:20 +1100 (AEDT)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 139384BB3BDE\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 24 Mar 2026 15:19:18 +0000 (GMT)","from mail-lf1-f42.google.com (mail-lf1-f42.google.com\n [209.85.167.42])\n by sourceware.org (Postfix) with ESMTPS id D43DF4B9DB6F\n for <gcc-patches@gcc.gnu.org>; Tue, 24 Mar 2026 15:18:45 +0000 (GMT)","by mail-lf1-f42.google.com with SMTP id\n 2adb3069b0e04-59e58404f28so340709e87.2\n for <gcc-patches@gcc.gnu.org>; Tue, 24 Mar 2026 08:18:45 -0700 (PDT)","from ubuntu-focal.. ([2a01:4f9:3a:1e26::2])\n by smtp.gmail.com with ESMTPSA id\n 2adb3069b0e04-5a298cadf1esm461870e87.29.2026.03.24.08.18.43\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 24 Mar 2026 08:18:43 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 139384BB3BDE","OpenDKIM Filter v2.11.0 sourceware.org D43DF4B9DB6F"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org D43DF4B9DB6F","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org D43DF4B9DB6F","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774365526; cv=none;\n b=ha9XC8nem573xrCYFiVwVsfnIlseb+s06umBtusTF0vlg7nIug1JHlWT4f4wwHhVNldk/AyQy1r1ahLTJN8nYe1+V+jbKqtUKCRoCiCh8dgxSTtCnQ5FdgE7EkJ7VkXT6xLd0DCxoXF6EwGFM0FkkF6BtZTY3/wvm0eCuOj+cIU=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1774365526; c=relaxed/simple;\n bh=AKRYOEsIHgYNpRparENrug2ldPVxnDFI/zWvjbG1Yrs=;\n h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version;\n b=uAxEiUsAkkxzHDYCxRUoQ019MWNrR9TV/IWO0Pox6HsrYdslD7/AHwK3lA8lgYZsLn9TclviEoe6/363y2RInmQbf/s7C7uhJuIGoHCEowwUunpiWDkWG8XextP7yj5/ysuBOlIMID4KENTq48+4Q8zkOb3eW5lOXd98qrp03ck=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=vrull.eu; s=google; t=1774365524; x=1774970324; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=HYiF7HOrX9xoGJQDqS59dSO4oSvnoVyfwhIyMojrm+w=;\n b=Fychp7vWL5YYZrM4YCq5pss827m5fMIxxpxBgZsrc47n7YGLAWK+1aRNsnBJiw0v5J\n rjzAkLsL+/EhRTLIz7mID6r7R4rSNRqo7hi0spd7LYYgaBl7QQj/i7gKEwvl3T8Gd0JC\n 0FksXY1fLsPt2nYt9LXrpdrT4QylKkIQdN2/zY2xlkAHrEYm4T2U+Ill4l3S+9OgiSut\n Y2ulAm/EEE1uGy/7p+v+42XSjqVXd7P0OL/IE6YyyltQc0CxtTgAnaV/zsYIUkXSaYGi\n TCxialYYVo++1qYZploCNtHMMUceY0fVELCXzw0BE9cTjmgse5AqtkkGwiWTnt8R8NdO\n C7LA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1774365524; x=1774970324;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=HYiF7HOrX9xoGJQDqS59dSO4oSvnoVyfwhIyMojrm+w=;\n b=JIMBHQdD5A9b20YLkkvDMYy95I2KFqKstVvxwevMdKEfVRXekReFRCu82Fovp6jjX+\n 8ZoykoV9QE6xOVqJ8Og9b90G0pcXtaYQXZF6n0ObLd2QXFzbzzom1X5Iw12QhhGxQkqH\n i7G67VsgICK1czukQ91VrplYQJvQmRBDZlqEiNRND/fph/KyTyQGf3yR2QvZnO8lmzKE\n Zo07NC/w09FREMxsylnM2N+U78rU0mNqjDEWHPUemsFk0bkgJspa7pVLaRrkG2NpaI+R\n VePqjAc7caZBjZTF7WOeCqkO6h2Q7GPrC/ypTVTBzXC5nLjYggtSu/SyAg5O9WCN/e0U\n CkiA==","X-Gm-Message-State":"AOJu0Yz8o578jWMOyIJtjyj9uYkApvT6W4XycUHeqW1TH7siYd0t5Qbw\n VAVKapvk5KLlUoZ6y/FG+P8b3T4hwgmtV0xgUVm+MSTjEkcKN+yNrJrCnA33kN6y8hQUwLlM+Rh\n yivdS","X-Gm-Gg":"ATEYQzw5M7noBzd4NDl9WltPdq44cFAaLeTYxa0QbQoCDKq3C077f6YBBX8gVaiIsWh\n Kv7IdxYZB67OZDeRiOvu6/rRKJ/cW/2jQ0pHRc/K87m1YLCP8VK4k/Iv39xyDfKsn/JqSeF0BEq\n oU9d5wcOk9lYycQNIRcEdYIIS4byYUGttS4FqXkHxI1qSgeEIr2AA8MVc3RG+Vaq18a1LCcE4cj\n saka7QNZ21DVnOdbveDh5zKqJHzeASaWDmQfX3sMojgDCWQci7ltFgEsKzbgbMTud6zVP9qHatc\n ez7NqqJn0O5Oz1YbMJ35MlwQ4k1fdgSKEObpB1wIH+Yt+VHkvbHQmQZhTW+hP9D3oWqa+ISF+y9\n OWubHL1YhD8w7mWyTJKta9F2YUs4yx4gC7ywthZTBWhotHHKfNHQTmApek4TGn26S0JPhTqtLUU\n t/r/M+H3CT4dtMeHzjfO+oSBvDDG/lxOizsHvNNCYLcYoLmMG0BplH","X-Received":"by 2002:a05:6512:238d:b0:5a1:3921:ab52 with SMTP id\n 2adb3069b0e04-5a285af5423mr2376344e87.2.1774365523726;\n Tue, 24 Mar 2026 08:18:43 -0700 (PDT)","From":"Philipp Tomsich <philipp.tomsich@vrull.eu>","To":"gcc-patches@gcc.gnu.org","Cc":"jeffrey.law@oss.qualcomm.com,\n Konstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu>,\n Philipp Tomsich <philipp.tomsich@vrull.eu>","Subject":"[PATCH GCC17-stage1] RISC-V: Synthesize FP constants via integer\n instructions + fmv","Date":"Tue, 24 Mar 2026 16:18:40 +0100","Message-Id":"<20260324151840.3671675-1-philipp.tomsich@vrull.eu>","X-Mailer":"git-send-email 2.34.1","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","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":"From: Konstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu>\n\nNon-zero floating-point constants that are not Zfa FLI candidates are\ncurrently always loaded from the constant pool (lui + flw/fld), even\nwhen the IEEE 754 bit pattern can be cheaply built in a GP register\nand transferred via fmv.s.x/fmv.d.x with no memory access.\n\nAdd expand-time synthesis in riscv_legitimize_move: decompose the\nCONST_DOUBLE into an integer build (riscv_move_integer) followed by\na GP-to-FP transfer.  The constant is synthesized when the integer\nbuild cost is < 3 instructions, keeping the total (including fmv)\nat <= 3 — competitive with the 2-instruction + memory-access\nconstant pool alternative.\n\nFor SFmode (RV32 and RV64 with F), every float constant qualifies\nsince any 32-bit value can be built in at most 2 instructions.\nFor DFmode (RV64 with D), constants whose bit pattern can be built\nin 1-2 instructions are covered: all powers of 2, simple fractions,\nsmall integers, and many common engineering constants.  Transcendental\nconstants like pi and e still use the constant pool.\n\nExamples (RV64GC, -O2):\n  1.0f:  lui+flw (2 insns + mem)  ->  li+fmv.s.x     (2 insns)\n  1.0:   lui+fld (2 insns + mem)  ->  li+slli+fmv.d.x (3 insns)\n  pi:    unchanged (constant pool, integer build too expensive)\n\ngcc/ChangeLog:\n\n\t* config/riscv/riscv.cc (riscv_reinterpret_float_as_int): New\n\tfunction to extract IEEE 754 bit pattern from CONST_DOUBLE.\n\t(riscv_float_const_rtx_p): New function to decide if integer\n\tsynthesis is profitable; returns the sign-extended integer\n\tvalue through an output parameter.\n\t(riscv_cannot_force_const_mem): Return true for synthesizable\n\tFP constants to prevent constant pool spilling.\n\t(riscv_const_insns): Return synthesis cost for eligible FP\n\tconstants so they are treated as legitimate constants.\n\t(riscv_legitimize_move): Add synthesis of FP constants via\n\tinteger instructions and fmv.[sd].x.\n\ngcc/testsuite/ChangeLog:\n\n\t* gcc.dg/fold-overflow-1.c: Expect 2139095040 three times on\n\tRISC-V due to FP constant synthesis of FLT_MAX.\n\t* gcc.target/riscv/pr105666.c: Remove scan-assembler-not for\n\tfmv.d.x since it now appears for FP constant synthesis.  Keep\n\tthe fmv.x.d check for GP-to-FP spill avoidance.\n\t* gcc.target/riscv/fp-const-synth-df-boundary.c: New test.\n\t* gcc.target/riscv/fp-const-synth-df-rv32.c: New test.\n\t* gcc.target/riscv/fp-const-synth-df.c: New test.\n\t* gcc.target/riscv/fp-const-synth-run.c: New test.\n\t* gcc.target/riscv/fp-const-synth-sf-rv32.c: New test.\n\t* gcc.target/riscv/fp-const-synth-sf.c: New test.\n\t* gcc.target/riscv/fp-const-synth-special-sf.c: New test.\n\t* gcc.target/riscv/fp-const-synth-zfa.c: New test.\n\nCo-authored-by: Philipp Tomsich <philipp.tomsich@vrull.eu>\n---\n gcc/config/riscv/riscv.cc                     | 131 +++++++++++++++++-\n gcc/testsuite/gcc.dg/fold-overflow-1.c        |   5 +-\n .../riscv/fp-const-synth-df-boundary.c        |  18 +++\n .../gcc.target/riscv/fp-const-synth-df-rv32.c |  14 ++\n .../gcc.target/riscv/fp-const-synth-df.c      |  29 ++++\n .../gcc.target/riscv/fp-const-synth-run.c     |  56 ++++++++\n .../gcc.target/riscv/fp-const-synth-sf-rv32.c |  34 +++++\n .../gcc.target/riscv/fp-const-synth-sf.c      |  34 +++++\n .../riscv/fp-const-synth-special-sf.c         |  21 +++\n .../gcc.target/riscv/fp-const-synth-zfa.c     |  23 +++\n gcc/testsuite/gcc.target/riscv/pr105666.c     |   3 +-\n 11 files changed, 361 insertions(+), 7 deletions(-)\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-df-boundary.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-df-rv32.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-df.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-run.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-sf-rv32.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-sf.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-special-sf.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fp-const-synth-zfa.c","diff":"diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc\nindex ff46ffdb4566..b45c48560fb2 100644\n--- a/gcc/config/riscv/riscv.cc\n+++ b/gcc/config/riscv/riscv.cc\n@@ -2025,6 +2025,74 @@ riscv_float_const_rtx_index_for_fli (rtx x)\n   return -1;\n }\n \n+/* Return the bit representation of floating-point constant X in *IVAL.\n+   Return false if X cannot be handled (unsupported mode or missing\n+   hardware support for the transfer).  */\n+\n+static bool\n+riscv_reinterpret_float_as_int (rtx x, unsigned HOST_WIDE_INT *ival)\n+{\n+  if (!CONST_DOUBLE_P (x))\n+    return false;\n+\n+  scalar_float_mode mode;\n+  if (!is_a<scalar_float_mode> (GET_MODE (x), &mode))\n+    return false;\n+\n+  /* SFmode: need fmv.s.x (base F extension).\n+     DFmode: need fmv.d.x (only on RV64 with D extension).  */\n+  if (mode == SFmode && !TARGET_HARD_FLOAT)\n+    return false;\n+  if (mode == DFmode && !(TARGET_64BIT && TARGET_DOUBLE_FLOAT))\n+    return false;\n+  if (mode != SFmode && mode != DFmode)\n+    return false;\n+\n+  long res[2];\n+  real_to_target (res, CONST_DOUBLE_REAL_VALUE (x),\n+\t\t  REAL_MODE_FORMAT (mode));\n+\n+  if (mode == DFmode)\n+    {\n+      int order = BYTES_BIG_ENDIAN ? 1 : 0;\n+      *ival = zext_hwi (res[order], 32);\n+      *ival |= (zext_hwi (res[1 - order], 32) << 32);\n+    }\n+  else\n+    *ival = zext_hwi (res[0], 32);\n+\n+  return true;\n+}\n+\n+/* Return true if the floating-point constant X can be synthesized with\n+   integer instructions and an fmv.[sd].x at a cost less than loading\n+   from the constant pool.  */\n+\n+static bool\n+riscv_float_const_rtx_p (rtx x, HOST_WIDE_INT *sival,\n+\t\t\t bool allow_new_pseudos = false)\n+{\n+  unsigned HOST_WIDE_INT ival;\n+  if (!riscv_reinterpret_float_as_int (x, &ival))\n+    return false;\n+\n+  /* For SFmode, sign-extend the 32-bit pattern to match what LUI\n+     produces on RV64.  fmv.s.x only reads the low 32 bits, so the\n+     upper bits don't matter for correctness.  */\n+  HOST_WIDE_INT val = (GET_MODE (x) == SFmode)\n+\t\t      ? sext_hwi (ival, 32)\n+\t\t      : (HOST_WIDE_INT) ival;\n+\n+  /* Threshold: integer build must take < 3 insns.  Adding 1 for fmv\n+     gives total <= 3.  The constant pool alternative (lui + fld/flw)\n+     costs 2 insns + a memory access + a constant pool entry.  */\n+  if (riscv_integer_cost (val, allow_new_pseudos) >= 3)\n+    return false;\n+\n+  *sival = val;\n+  return true;\n+}\n+\n /* Implement TARGET_LEGITIMATE_CONSTANT_P.  */\n \n static bool\n@@ -2059,6 +2127,12 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)\n   if (satisfies_constraint_zfli (x))\n    return true;\n \n+  /* FP constants that can be synthesized via integer instructions + fmv\n+     should not be spilled to the constant pool.  */\n+  HOST_WIDE_INT sival;\n+  if (riscv_float_const_rtx_p (x, &sival))\n+    return true;\n+\n   split_const (x, &base, &offset);\n   if (riscv_symbolic_constant_p (base, &type))\n     {\n@@ -2610,12 +2684,23 @@ riscv_const_insns (rtx x, bool allow_new_pseudos)\n       }\n \n     case CONST_DOUBLE:\n-      /* See if we can use FMV directly.  */\n-      if (satisfies_constraint_zfli (x))\n-\treturn 1;\n+      {\n+\t/* See if we can use FMV directly.  */\n+\tif (satisfies_constraint_zfli (x))\n+\t  return 1;\n \n-      /* We can use x0 to load floating-point zero.  */\n-      return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;\n+\t/* We can use x0 to load floating-point zero.  */\n+\tif (x == CONST0_RTX (GET_MODE (x)))\n+\t  return 1;\n+\n+\t/* Check if we can synthesize via integer instructions + fmv.  */\n+\tHOST_WIDE_INT sival;\n+\tif (riscv_float_const_rtx_p (x, &sival, allow_new_pseudos))\n+\t  /* Integer build cost + 1 for fmv.  */\n+\t  return riscv_integer_cost (sival, allow_new_pseudos) + 1;\n+\n+\treturn 0;\n+      }\n     case CONST_VECTOR:\n       {\n \t/* TODO: This is not accurate, we will need to\n@@ -4012,6 +4097,42 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src)\n       return true;\n     }\n \n+  /* Synthesize FP constants via integer instructions + fmv.[sd].x\n+     when cheaper than a constant pool load.\n+     This requires pseudos, so it is skipped post-reload.  That is safe:\n+     riscv_const_insns returns nonzero for these constants, so they are\n+     legitimate and accepted by move_operand; the move pattern then\n+     handles them without going through riscv_legitimize_const_move.  */\n+  HOST_WIDE_INT sival;\n+  if (CONST_DOUBLE_P (src)\n+      && SCALAR_FLOAT_MODE_P (mode)\n+      && REG_P (dest)\n+      && can_create_pseudo_p ()\n+      && !satisfies_constraint_zfli (src)\n+      && src != CONST0_RTX (mode)\n+      && riscv_float_const_rtx_p (src, &sival, true))\n+    {\n+      rtx int_reg = gen_reg_rtx (word_mode);\n+      riscv_move_integer (int_reg, int_reg, sival, word_mode);\n+\n+      /* Float subregs must have the same size as their inner register\n+\t (validate_subreg rejects e.g. (subreg:SF (reg:DI) 0)).\n+\t When word_mode is wider than the float mode, copy to a\n+\t matching-size integer pseudo first.  */\n+      scalar_int_mode imode = int_mode_for_mode (mode).require ();\n+      rtx transfer_reg;\n+      if (maybe_ne (GET_MODE_SIZE (word_mode), GET_MODE_SIZE (imode)))\n+\t{\n+\t  transfer_reg = gen_reg_rtx (imode);\n+\t  riscv_emit_move (transfer_reg, gen_lowpart (imode, int_reg));\n+\t}\n+      else\n+\ttransfer_reg = int_reg;\n+\n+      riscv_emit_move (dest, gen_lowpart (mode, transfer_reg));\n+      return true;\n+    }\n+\n   /* We need to deal with constants that would be legitimate\n      immediate_operands but aren't legitimate move_operands.  */\n   if (CONSTANT_P (src) && !move_operand (src, mode))\ndiff --git a/gcc/testsuite/gcc.dg/fold-overflow-1.c b/gcc/testsuite/gcc.dg/fold-overflow-1.c\nindex 108df4e3155f..48718961c28b 100644\n--- a/gcc/testsuite/gcc.dg/fold-overflow-1.c\n+++ b/gcc/testsuite/gcc.dg/fold-overflow-1.c\n@@ -18,5 +18,8 @@ float foo2(void)\n   return 1.0f/0.0f;\n }\n \n-/* { dg-final { scan-assembler-times \"2139095040\" 2 { target { ! mmix-*-* } } } } */\n+/* On RISC-V, FLT_MAX (0x7F7FFFFF) is synthesized as lui 0x7F800 + addi -1,\n+   so 2139095040 (0x7F800000) appears once more as an instruction operand.  */\n+/* { dg-final { scan-assembler-times \"2139095040\" 3 { target { riscv*-*-* } } } } */\n+/* { dg-final { scan-assembler-times \"2139095040\" 2 { target { ! { mmix-*-* || riscv*-*-* } } } } } */\n /* { dg-final { scan-assembler-times \"#7f800000\" 2 { target mmix-*-* } } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-boundary.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-boundary.c\nnew file mode 100644\nindex 000000000000..49321e8ef3fa\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-boundary.c\n@@ -0,0 +1,18 @@\n+/* Verify that DFmode constants at the synthesis cost boundary\n+   (integer build cost == 3, exceeding the < 3 threshold) fall\n+   back to the constant pool.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -O2\" } */\n+\n+/* 1.0 + 1 ULP = 0x3FF0000000000001.\n+   Unlike 1.0 (0x3FF0000000000000, cost 2: lui+slli), the low\n+   bit makes the pattern cost >= 3 integer instructions.  */\n+double ret_one_plus_ulp (void) { return 0x1.0000000000001p+0; }\n+\n+/* -1.0 + 1 ULP in magnitude = 0xBFF0000000000001.  */\n+double ret_neg_one_plus_ulp (void) { return -0x1.0000000000001p+0; }\n+\n+/* Must use constant pool.  */\n+/* { dg-final { scan-assembler-times {\\tfld\\t} 2 } } */\n+/* Must not use synthesis.  */\n+/* { dg-final { scan-assembler-not {\\tfmv\\.d\\.x\\tfa0,a} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-rv32.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-rv32.c\nnew file mode 100644\nindex 000000000000..4e6167f9dabb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df-rv32.c\n@@ -0,0 +1,14 @@\n+/* Verify that DFmode constants on RV32 use the constant pool,\n+   since fmv.d.x is only available on RV64.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv32gc -mabi=ilp32d -O2\" } */\n+\n+double ret_one (void) { return 1.0; }\n+double ret_neg_one (void) { return -1.0; }\n+double ret_two (void) { return 2.0; }\n+double ret_half (void) { return 0.5; }\n+\n+/* DFmode must use constant pool loads on RV32.  */\n+/* { dg-final { scan-assembler-times {\\tfld\\t} 4 } } */\n+/* fmv.d.x is not available on RV32.  */\n+/* { dg-final { scan-assembler-not {\\tfmv\\.d\\.x\\t} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-df.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df.c\nnew file mode 100644\nindex 000000000000..7a0ab1bcbdce\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-df.c\n@@ -0,0 +1,29 @@\n+/* Verify that DFmode constants with cheap 64-bit bit patterns are\n+   synthesized via integer instructions + fmv.d.x, while constants\n+   with expensive patterns still use the constant pool.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -O2\" } */\n+\n+/* Positive: powers of 2 and simple fractions — li+slli (cost 2) + fmv.  */\n+double ret_one (void) { return 1.0; }\n+double ret_neg_one (void) { return -1.0; }\n+double ret_two (void) { return 2.0; }\n+double ret_half (void) { return 0.5; }\n+\n+/* Positive: negative zero — li+slli (cost 2) + fmv.  */\n+double ret_neg_zero (void) { return -0.0; }\n+\n+/* Negative: transcendentals — bit patterns too complex (cost >= 3).  */\n+double ret_pi (void) { return 3.14159265358979323846; }\n+double ret_e (void) { return 2.71828182845904523536; }\n+double ret_1_1 (void) { return 1.1; }\n+\n+/* Boundary: +0.0 must use fmv.d.x from x0, not synthesis.  */\n+double ret_zero (void) { return 0.0; }\n+\n+/* Synthesized DFmode constants use fmv.d.x with a GP source.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.d\\.x\\tfa0,a[0-9]+} 5 } } */\n+/* +0.0 should use fmv.d.x from the zero register.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.d\\.x\\tfa0,zero} 1 } } */\n+/* Expensive constants must use constant pool loads.  */\n+/* { dg-final { scan-assembler-times {\\tfld\\t} 3 } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-run.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-run.c\nnew file mode 100644\nindex 000000000000..df497f5dda66\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-run.c\n@@ -0,0 +1,56 @@\n+/* Runtime verification that synthesized FP constants are bit-exact.  */\n+/* { dg-do run } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -O2\" } */\n+\n+typedef __UINT32_TYPE__ uint32_t;\n+typedef __UINT64_TYPE__ uint64_t;\n+\n+static inline uint32_t\n+float_bits (float f)\n+{\n+  uint32_t u;\n+  __builtin_memcpy (&u, &f, sizeof u);\n+  return u;\n+}\n+\n+static inline uint64_t\n+double_bits (double d)\n+{\n+  uint64_t u;\n+  __builtin_memcpy (&u, &d, sizeof u);\n+  return u;\n+}\n+\n+/* Prevent inlining so constants are materialized in registers.  */\n+float __attribute__ ((noinline)) ret_one_f (void) { return 1.0f; }\n+float __attribute__ ((noinline)) ret_neg_one_f (void) { return -1.0f; }\n+float __attribute__ ((noinline)) ret_neg_zero_f (void) { return -0.0f; }\n+float __attribute__ ((noinline)) ret_inf_f (void) { return __builtin_inff (); }\n+\n+double __attribute__ ((noinline)) ret_one (void) { return 1.0; }\n+double __attribute__ ((noinline)) ret_neg_one (void) { return -1.0; }\n+double __attribute__ ((noinline)) ret_neg_zero (void) { return -0.0; }\n+\n+int\n+main (void)\n+{\n+  /* SFmode: all synthesized via integer instructions + fmv.s.x.  */\n+  if (float_bits (ret_one_f ()) != 0x3F800000U)\n+    __builtin_abort ();\n+  if (float_bits (ret_neg_one_f ()) != 0xBF800000U)\n+    __builtin_abort ();\n+  if (float_bits (ret_neg_zero_f ()) != 0x80000000U)\n+    __builtin_abort ();\n+  if (float_bits (ret_inf_f ()) != 0x7F800000U)\n+    __builtin_abort ();\n+\n+  /* DFmode: synthesized (cost-2 patterns) via integer + fmv.d.x.  */\n+  if (double_bits (ret_one ()) != 0x3FF0000000000000ULL)\n+    __builtin_abort ();\n+  if (double_bits (ret_neg_one ()) != 0xBFF0000000000000ULL)\n+    __builtin_abort ();\n+  if (double_bits (ret_neg_zero ()) != 0x8000000000000000ULL)\n+    __builtin_abort ();\n+\n+  return 0;\n+}\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf-rv32.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf-rv32.c\nnew file mode 100644\nindex 000000000000..37a30e3469ae\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf-rv32.c\n@@ -0,0 +1,34 @@\n+/* Verify that non-zero SFmode constants are synthesized via integer\n+   instructions + fmv.s.x rather than loaded from the constant pool.\n+   On RV32, any 32-bit float bit pattern can be built in at most 2\n+   integer instructions, so synthesis always wins over lui+flw.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv32gc -mabi=ilp32f -O2\" } */\n+\n+/* Positive: common constants — single li (cost 1) + fmv.  */\n+float ret_one (void) { return 1.0f; }\n+float ret_neg_one (void) { return -1.0f; }\n+float ret_two (void) { return 2.0f; }\n+float ret_half (void) { return 0.5f; }\n+\n+/* Positive: negative zero — li (cost 1) + fmv.  */\n+float ret_neg_zero (void) { return -0.0f; }\n+\n+/* Positive: pi — li+addi (cost 2) + fmv.  */\n+float ret_pi (void) { return 3.14159265f; }\n+\n+/* Positive: smallest normal float (2^-126).  */\n+float ret_flt_min (void) { return 1.17549435e-38f; }\n+\n+/* Positive: large exponent, low 12 bits zero.  */\n+float ret_65536 (void) { return 65536.0f; }\n+\n+/* Boundary: +0.0 must use fmv.s.x from x0, not synthesis.  */\n+float ret_zero (void) { return 0.0f; }\n+\n+/* All non-zero SFmode returns should use fmv.s.x with a GP source.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.s\\.x\\tfa0,a[0-9]+} 8 } } */\n+/* +0.0 should use fmv.s.x from the zero register.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.s\\.x\\tfa0,zero} 1 } } */\n+/* No constant pool loads (flw) should appear.  */\n+/* { dg-final { scan-assembler-not {\\tflw\\t} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf.c\nnew file mode 100644\nindex 000000000000..6e71c9fbb043\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-sf.c\n@@ -0,0 +1,34 @@\n+/* Verify that non-zero SFmode constants are synthesized via integer\n+   instructions + fmv.s.x rather than loaded from the constant pool.\n+   On RV64, any 32-bit float bit pattern can be built in at most 2\n+   integer instructions, so synthesis always wins over lui+flw.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -O2\" } */\n+\n+/* Positive: common constants — single li (cost 1) + fmv.  */\n+float ret_one (void) { return 1.0f; }\n+float ret_neg_one (void) { return -1.0f; }\n+float ret_two (void) { return 2.0f; }\n+float ret_half (void) { return 0.5f; }\n+\n+/* Positive: negative zero — li (cost 1) + fmv.  */\n+float ret_neg_zero (void) { return -0.0f; }\n+\n+/* Positive: pi — li+addi (cost 2) + fmv.  */\n+float ret_pi (void) { return 3.14159265f; }\n+\n+/* Positive: smallest normal float (2^-126).  */\n+float ret_flt_min (void) { return 1.17549435e-38f; }\n+\n+/* Positive: large exponent, low 12 bits zero.  */\n+float ret_65536 (void) { return 65536.0f; }\n+\n+/* Boundary: +0.0 must use fmv.s.x from x0, not synthesis.  */\n+float ret_zero (void) { return 0.0f; }\n+\n+/* All non-zero SFmode returns should use fmv.s.x with a GP source.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.s\\.x\\tfa0,a[0-9]+} 8 } } */\n+/* +0.0 should use fmv.s.x from the zero register.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.s\\.x\\tfa0,zero} 1 } } */\n+/* No constant pool loads (flw) should appear.  */\n+/* { dg-final { scan-assembler-not {\\tflw\\t} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-special-sf.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-special-sf.c\nnew file mode 100644\nindex 000000000000..8c870eb0ee4a\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-special-sf.c\n@@ -0,0 +1,21 @@\n+/* Verify synthesis of special IEEE 754 SFmode values (infinity,\n+   NaN, subnormals) via integer instructions + fmv.s.x.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -O2\" } */\n+\n+/* +inf: 0x7F800000 -- li (cost 1) + fmv.  */\n+float ret_inf (void) { return __builtin_inff (); }\n+\n+/* -inf: 0xFF800000 -- li (cost 1) + fmv.  */\n+float ret_neg_inf (void) { return -__builtin_inff (); }\n+\n+/* quiet NaN: 0x7FC00000 -- li (cost 1) + fmv.  */\n+float ret_qnan (void) { return __builtin_nanf (\"\"); }\n+\n+/* Smallest subnormal: 0x00000001 -- addi (cost 1) + fmv.  */\n+float ret_subnorm_min (void) { return __FLT_DENORM_MIN__; }\n+\n+/* All should use fmv.s.x with a GP source.  */\n+/* { dg-final { scan-assembler-times {\\tfmv\\.s\\.x\\tfa0,a[0-9]+} 4 } } */\n+/* No constant pool loads should appear.  */\n+/* { dg-final { scan-assembler-not {\\tflw\\t} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/fp-const-synth-zfa.c b/gcc/testsuite/gcc.target/riscv/fp-const-synth-zfa.c\nnew file mode 100644\nindex 000000000000..ae43167b9ef2\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fp-const-synth-zfa.c\n@@ -0,0 +1,23 @@\n+/* Verify that FLI-eligible constants use fli.[sd] with Zfa\n+   rather than the integer synthesis path.  */\n+/* { dg-do compile } */\n+/* { dg-options \"-march=rv64gc_zfa -mabi=lp64d -O2\" { target { rv64 } } } */\n+/* { dg-options \"-march=rv32gc_zfa -mabi=ilp32d -O2\" { target { rv32 } } } */\n+\n+#ifndef __riscv_zfa\n+#error Feature macro not defined\n+#endif\n+\n+float ret_one_f (void) { return 1.0f; }\n+float ret_half_f (void) { return 0.5f; }\n+float ret_two_f (void) { return 2.0f; }\n+\n+double ret_one (void) { return 1.0; }\n+double ret_half (void) { return 0.5; }\n+double ret_two (void) { return 2.0; }\n+\n+/* FLI-eligible constants must use fli, not synthesis.  */\n+/* { dg-final { scan-assembler-times {\\tfli\\.s\\t} 3 } } */\n+/* { dg-final { scan-assembler-times {\\tfli\\.d\\t} 3 } } */\n+/* No integer-to-FP synthesis should occur for these values.  */\n+/* { dg-final { scan-assembler-not {\\tfmv\\.[sd]\\.x\\tfa0,a} } } */\ndiff --git a/gcc/testsuite/gcc.target/riscv/pr105666.c b/gcc/testsuite/gcc.target/riscv/pr105666.c\nindex 752bbf1c0172..59ea942a9662 100644\n--- a/gcc/testsuite/gcc.target/riscv/pr105666.c\n+++ b/gcc/testsuite/gcc.target/riscv/pr105666.c\n@@ -52,5 +52,6 @@ main (void)\n   return 0;\n }\n \n-/* { dg-final { scan-assembler-not \"\\tfmv\\\\.d\\\\.x\\t\" } } */\n+/* fmv.d.x is now expected for FP constant synthesis via integer insns.\n+   The key check is that fmv.x.d (FP->GP spill) doesn't appear.  */\n /* { dg-final { scan-assembler-not \"\\tfmv\\\\.x\\\\.d\\t\" } } */\n","prefixes":["GCC17-stage1"]}