[PATCH 4/6] arm: Add Thumb-1 BFmode moves to fix __bf16 ICE [PR99764]

Dominic P <[email protected]> Sun, 2 Aug 2026 11:56:06 +0100
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
The Thumb-1 16-bit move pattern *thumb1_movhf only accepted HFmode, so a
__bf16 (BFmode) value on a Thumb-1 target -- e.g. -mcpu=cortex-m1, or any
armv4t/armv6-m -mthumb configuration -- had no move insn.  A bare load,
store or register move of a __bf16 therefore reached RTL and aborted:

  internal compiler error: in extract_insn, at recog.cc:2894

BFmode and HFmode are both opaque 16-bit storage types as far as a move is
concerned (a plain 16-bit copy, no interpretation), and the ARM/Thumb-2
mover *arm32_mov<mode> already handles both via the HFBF iterator.  Extend
the Thumb-1 pattern the same way so __bf16 storage works on Thumb-1 exactly
like __fp16, turning the ICE into ordinary ldrh/strh/movs code.

Assisted-by: Claude Opus 5 (Anthropic)

gcc/ChangeLog:

	PR target/99764
	* config/arm/thumb1.md (*thumb1_movhf): Rename to...
	(*thumb1_mov<mode>): ...this, using the HFBF mode iterator so it
	also handles BFmode.

gcc/testsuite/ChangeLog:

	PR target/99764
	* gcc.target/arm/pr99764.c: New test.

Signed-off-by: Dominic P <[email protected]>
---
 gcc/config/arm/thumb1.md               | 12 ++++-----
 gcc/testsuite/gcc.target/arm/pr99764.c | 37 ++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arm/pr99764.c

diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 0c704c5d8..f6d2851c9 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -907,12 +907,12 @@
    (set_attr "pool_range" "*,32,*,*,*,*")
    (set_attr "conds" "clob,nocond,nocond,nocond,nocond,clob")])
 
-(define_insn "*thumb1_movhf"
-  [(set (match_operand:HF     0 "nonimmediate_operand" "=l,l,l,m,*r,*h")
-	(match_operand:HF     1 "general_operand"      "l, m,F,l,*h,*r"))]
+(define_insn "*thumb1_mov<mode>"
+  [(set (match_operand:HFBF   0 "nonimmediate_operand" "=l,l,l,m,*r,*h")
+	(match_operand:HFBF   1 "general_operand"      "l, m,F,l,*h,*r"))]
   "TARGET_THUMB1
-   && (	  s_register_operand (operands[0], HFmode)
-       || s_register_operand (operands[1], HFmode))"
+   && (	  s_register_operand (operands[0], <MODE>mode)
+       || s_register_operand (operands[1], <MODE>mode))"
   "*
   switch (which_alternative)
     {
@@ -941,7 +941,7 @@
       rtx ops[3];
 
       bits = real_to_target (NULL, CONST_DOUBLE_REAL_VALUE (operands[1]),
-			     HFmode);
+			     <MODE>mode);
       ops[0] = operands[0];
       high = (bits >> 8) & 0xff;
       ops[1] = GEN_INT (high);
diff --git a/gcc/testsuite/gcc.target/arm/pr99764.c b/gcc/testsuite/gcc.target/arm/pr99764.c
new file mode 100644
index 000000000..8906366b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr99764.c
@@ -0,0 +1,37 @@
+/* PR target/99764: moving a __bf16 value on a Thumb-1 target used to ICE
+   in extract_insn ("unrecognizable insn") because the Thumb-1 16-bit move
+   pattern only handled HFmode, leaving BFmode with no move insn.  A plain
+   load/store/move of a __bf16 must compile cleanly, exactly like __fp16.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mthumb" "-march=*" "-mcpu=*" } } */
+/* { dg-options "-mcpu=cortex-m1 -mfloat-abi=soft -O2" } */
+
+__bf16 g;
+
+void
+store (__bf16 a)
+{
+  g = a;
+}
+
+__bf16
+load (void)
+{
+  return g;
+}
+
+__bf16
+pass (__bf16 a, __bf16 b)
+{
+  return b;
+}
+
+__bf16
+viamem (__bf16 *p, __bf16 a)
+{
+  *p = a;
+  return p[1];
+}
+
+/* { dg-final { scan-assembler "strh" } } */
+/* { dg-final { scan-assembler "ldrh" } } */
-- 
2.55.0