]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
arm: avoid unmatched insn in movhfcc [PR118460]
authorRichard Earnshaw <rearnsha@arm.com>
Tue, 14 Oct 2025 12:53:05 +0000 (13:53 +0100)
committerRichard Earnshaw <rearnsha@arm.com>
Wed, 15 Oct 2025 15:55:36 +0000 (16:55 +0100)
When compiling for m-profile with the floating-point extension we have
a vsel instruction that takes a limited set of comparisons.  In most
cases we can use this with careful selection of the operand order, but
we need to expand things in the right way.  This patch is in two parts:

1) We validate that the expansion will produce correct RTL;
2) We canonicalize the comparison to increase the chances that the
above check will pass.

gcc:

PR target/118460
* config/arm/arm.cc (arm_canonicalize_comparison): For floating-
point comparisons, swap the operand order if that will be more
likely to produce a comparison that can be used with VSEL.
(arm_validize_comparison): Make sure that HFmode comparisons
are compatible with VSEL.

gcc/testsuite:

PR target/118460
* gcc.target/arm/armv8_2-fp16-move-1.c: Adjust expected output.
* gcc.target/arm/armv8_2-fp16-move-2.c: Likewise.

gcc/config/arm/arm.cc
gcc/testsuite/gcc.target/arm/armv8_2-fp16-move-1.c
gcc/testsuite/gcc.target/arm/armv8_2-fp16-move-2.c

index da28d96298a415bb2758eeae966e0045c2e6cec3..6df2fa02172c0aeb7c1db688ecb7c746dfac3be5 100644 (file)
@@ -5696,6 +5696,22 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
 
   maxval = (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (mode) - 1)) - 1;
 
+  /* For floating-point comparisons, prefer >= and > over <= and < since
+     the former are supported by VSEL on some architectures.  Only do this
+     if both operands are registers.  */
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && (*code == LE
+         || *code == LT
+         || *code == UNGT
+         || *code == UNGE)
+      && register_operand (*op0, mode)
+      && register_operand (*op1, mode))
+    {
+      std::swap (*op0, *op1);
+      *code = (int) swap_condition ((rtx_code)*code);
+      return;
+    }
+
   /* For DImode, we have GE/LT/GEU/LTU comparisons (with cmp/sbc).  In
      ARM mode we can also use cmp/cmpeq for GTU/LEU.  GT/LE must be
      either reversed or (for constant OP1) adjusted to GE/LT.
@@ -32478,6 +32494,9 @@ arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
     case E_HFmode:
       if (!TARGET_VFP_FP16INST)
        break;
+      if (!arm_vsel_comparison_operator (*comparison, mode))
+       return false;
+
       /* FP16 comparisons are done in SF mode.  */
       mode = SFmode;
       *op1 = convert_to_mode (mode, *op1, 1);
index 444c4a3353555f22828cbbeb6802a3f1a39c9df7..02d7b51ac8b911408d374528c078b6e9dc633aa9 100644 (file)
@@ -134,8 +134,8 @@ test_select_8 (__fp16 a, __fp16 b, __fp16 c)
 }
 
 /* { dg-final { scan-assembler-times {vseleq\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 4 } } */
-/* { dg-final { scan-assembler-times {vselgt\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } }  */
-/* { dg-final { scan-assembler-times {vselge\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } }  */
+/* { dg-final { scan-assembler-times {vselgt\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 2 } }  */
+/* { dg-final { scan-assembler-times {vselge\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 2 } }  */
 
 /* { dg-final { scan-assembler-not {vmov\.f16} } }  */
 
index dff57ac8147c2d3f450f7327c6999d2896c9e58c..a249d712119f884083ff2aa9130af0e28f6aff73 100644 (file)
@@ -8,4 +8,4 @@ test_select (__fp16 a, __fp16 b, __fp16 c)
 {
   return (a < b) ? b : c;
 }
-/* { dg-final { scan-assembler "bx?(mi|pl)" } } */
+/* { dg-final { scan-assembler "vselgt\.f16\t" } } */