https://gcc.gnu.org/g:5f3b5b0616fe883e86e95d9476371cf87059ca7f

commit r16-1280-g5f3b5b0616fe883e86e95d9476371cf87059ca7f
Author: Takayuki 'January June' Suwa <jjsuwa_sys3...@yahoo.co.jp>
Date:   Sun Jun 8 14:05:05 2025 +0900

    xtensa: Implement l(ceil|floor)sfsi2 insn patterns and their scaled variants
    
    By using the previously unused CEIL|FLOOR.S floating-point coprocessor
    instructions.  In addition, two instruction operand format codes are added
    to output the scale value as assembler source.
    
         /* example */
         int test0(float a) {
           return __builtin_lceilf(a);
         }
         int test1(float a) {
           return __builtin_lceilf(a * 2);
         }
         int test2(float a) {
           return __builtin_lfloorf(a);
         }
         int test3(float a) {
           return __builtin_lfloorf(a * 32768);
         }
    
         ;; result
         test0:
            entry   sp, 32
            wfr     f0, a2
            ceil.s  a2, f0, 0
            retw.n
         test1:
            entry   sp, 32
            wfr     f0, a2
            ceil.s  a2, f0, 1
            retw.n
         test2:
            entry   sp, 32
            wfr     f0, a2
            floor.s a2, f0, 0
            retw.n
         test3:
            entry   sp, 32
            wfr     f0, a2
            floor.s a2, f0, 15
            retw.n
    
    However, because the rounding-half behavior (e.g., the rule that determines
    whether 1.5 should be rounded to 1 or 2) of the two is inconsistent;
    the lroundsfsi2 pattern is explicitly specified that rounding to nearest
    integer and away from zero, but the other hand, the ROUND.S instruction is
    not specified that by the ISA and is implementation-dependent.
    
    Therefore lroundsfsi2 cannot be implemented by ROUND.S.
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa.cc (printx, print_operand):
            Add two instruction operand format codes 'U' and 'V',
            whose represent scale factors of 0 to 15th positive/negative
            power of two.
            * config/xtensa/xtensa.md (c_enum "unspec"):
            Add UNSPEC_CEIL and UNSPEC_FLOOR.
            (int_iterator ANY_ROUND, int_attr m_round):
            New integer iterator and its attribute.
            (fix<s_fix>_truncsfsi2, *fix<s_fix>_truncsfsi2_2x,
            *fix<s_fix>_truncsfsi2_scaled, float<s_float>sisf2,
            *float<s_float>sisf2_scaled):
            Use output templates with the operand formats added above,
            instead of individual output statements.
            (l<m_round>sfsi2, *l<m_round>sfsi2_2x, *l<m_round>sfsi2_scaled):
            New insn patterns.

Diff:
---
 gcc/config/xtensa/xtensa.cc | 16 +++++++++++++++
 gcc/config/xtensa/xtensa.md | 50 ++++++++++++++++++++++++++++++++++-----------
 2 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index a9d67a56cd6a..90b5ff93042f 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -3047,6 +3047,8 @@ xtensa_modes_tieable_p (machine_mode mode1, machine_mode 
mode2)
    'K'  CONST_INT, print number of bits in mask for EXTUI
    'R'  CONST_INT, print (X & 0x1f)
    'L'  CONST_INT, print ((32 - X) & 0x1f)
+   'U', CONST_DOUBLE:SF, print (REAL_EXP (rval) - 1)
+   'V', CONST_DOUBLE:SF, print (1 - REAL_EXP (rval))
    'D'  REG, print second register of double-word register operand
    'N'  MEM, print address of next word following a memory operand
    'v'  MEM, if memory reference is volatile, output a MEMW before it
@@ -3143,6 +3145,20 @@ print_operand (FILE *file, rtx x, int letter)
        output_operand_lossage ("invalid %%R value");
       break;
 
+    case 'U':
+      if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode)
+       fprintf (file, "%d", REAL_EXP (CONST_DOUBLE_REAL_VALUE (x)) - 1);
+      else
+       output_operand_lossage ("invalid %%U value");
+      break;
+
+    case 'V':
+      if (CONST_DOUBLE_P (x) && GET_MODE (x) == SFmode)
+       fprintf (file, "%d", 1 - REAL_EXP (CONST_DOUBLE_REAL_VALUE (x)));
+      else
+       output_operand_lossage ("invalid %%V value");
+      break;
+
     case 'x':
       if (CONST_INT_P (x))
        printx (file, INTVAL (x));
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index c7ac456ae5f3..56e222dddfd2 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -41,6 +41,8 @@
   UNSPEC_LSETUP_START
   UNSPEC_LSETUP_END
   UNSPEC_FRAME_BLOCKAGE
+  UNSPEC_CEIL
+  UNSPEC_FLOOR
 ])
 
 (define_c_enum "unspecv" [
@@ -103,6 +105,11 @@
 (define_code_attr m_float [(float "float") (unsigned_float "ufloat")])
 (define_code_attr s_float [(float "") (unsigned_float "uns")])
 
+;; This iterator and attribute allow FP-to-integer rounding of two types
+;; to be generated from one template.
+(define_int_iterator ANY_ROUND [UNSPEC_CEIL UNSPEC_FLOOR])
+(define_int_attr m_round [(UNSPEC_CEIL "ceil") (UNSPEC_FLOOR "floor")])
+
 
 ;; Attributes.
 
@@ -1168,12 +1175,7 @@
        (any_fix:SI (mult:SF (match_operand:SF 1 "register_operand" "f")
                             (match_operand:SF 2 "fix_scaling_operand" "F"))))]
   "TARGET_HARD_FLOAT"
-{
-  static char result[64];
-  sprintf (result, "<m_fix>.s\t%%0, %%1, %d",
-          REAL_EXP (CONST_DOUBLE_REAL_VALUE (operands[2])) - 1);
-  return result;
-}
+  "<m_fix>.s\t%0, %1, %U2"
   [(set_attr "type"    "fconv")
    (set_attr "mode"    "SF")
    (set_attr "length"  "3")])
@@ -1192,12 +1194,36 @@
        (mult:SF (any_float:SF (match_operand:SI 1 "register_operand" "a"))
                 (match_operand:SF 2 "float_scaling_operand" "F")))]
   "TARGET_HARD_FLOAT"
-{
-  static char result[64];
-  sprintf (result, "<m_float>.s\t%%0, %%1, %d",
-          1 - REAL_EXP (CONST_DOUBLE_REAL_VALUE (operands[2])));
-  return result;
-}
+  "<m_float>.s\t%0, %1, %V2"
+  [(set_attr "type"    "fconv")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "3")])
+
+(define_insn "l<m_round>sfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(match_operand:SF 1 "register_operand" "f")] ANY_ROUND))]
+  "TARGET_HARD_FLOAT"
+  "<m_round>.s\t%0, %1, 0"
+  [(set_attr "type"    "fconv")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "3")])
+
+(define_insn "*l<m_round>sfsi2_2x"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(plus:SF (match_operand:SF 1 "register_operand" "f")
+                            (match_dup 1))] ANY_ROUND))]
+  "TARGET_HARD_FLOAT"
+  "<m_round>.s\t%0, %1, 1"
+  [(set_attr "type"    "fconv")
+   (set_attr "mode"    "SF")
+   (set_attr "length"  "3")])
+
+(define_insn "*l<m_round>sfsi2_scaled"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(mult:SF (match_operand:SF 1 "register_operand" "f")
+                            (match_operand:SF 2 "fix_scaling_operand" "F"))] 
ANY_ROUND))]
+  "TARGET_HARD_FLOAT"
+  "<m_round>.s\t%0, %1, %U2"
   [(set_attr "type"    "fconv")
    (set_attr "mode"    "SF")
    (set_attr "length"  "3")])

Reply via email to