This patch adds support for negate, absolute value, and negative
absolute value.  It does this by doing IOR, XOR, and ANDC on the BF/HF
values.  In order to do this optimization, it also needs to define the
logical instructions for HFmode and BFmode.

2025-11-05  Michael Meissner  <[email protected]>

gcc/

        * config/rs6000/float16.md (neg<mode>2): Add BFmode/HFmode negate,
        absolute value and negative absolute value operations.  Add logical
        insns operating on BFmode/HFmode.
        (abs<mode>2): Likewise.
        (nabs<mode>2): Likewise.
        (and<mode>3): Likewise.
        (ior<mode>): Likewise.
        (xor<mode>3): Likewise.
        (nor<mode>3): Likewise.
        (andn<mode>3): Likewise.
        (eqv<mode>3): Likewise.
        (nand<mode>3): Likewise.
        (iorn<mode>3): Likewise.
        (bool<mode>3): Likewise.
        (boolc<mode>3): Likewise.
        (boolcc<mode>): Likewise.
---
 gcc/config/rs6000/float16.md | 213 +++++++++++++++++++++++++++++++++++
 1 file changed, 213 insertions(+)

diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md
index c828b5711fb..273848b28ed 100644
--- a/gcc/config/rs6000/float16.md
+++ b/gcc/config/rs6000/float16.md
@@ -472,3 +472,216 @@ (define_expand "fixuns_trunc<FP16_HW:mode><GPR:mode>2"
   emit_insn (gen_fixuns_truncdf<GPR:mode>2 (operands[0], df_tmp));
   DONE;
 })
+
+;; Negate 16-bit floating point by XOR with -0.0.
+
+(define_insn_and_split "neg<mode>2"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,?wr")
+       (neg:FP16 (match_operand:FP16 1 "gpc_reg_operand" "wa,wr")))
+   (clobber (match_scratch:FP16 2 "=&wa,&r"))]
+  ""
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+       (match_dup 3))
+   (set (match_dup 0)
+       (xor:FP16 (match_dup 1)
+                 (match_dup 2)))]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (<MODE>mode);
+
+  REAL_VALUE_TYPE dconst;
+
+  gcc_assert (real_from_string (&dconst, "-0.0") == 0);
+
+  rtx rc = const_double_from_real_value (dconst, <MODE>mode);
+  if (!TARGET_PREFIXED)
+    rc = force_const_mem (<MODE>mode, rc);
+
+  operands[3] = rc;
+}
+  [(set_attr "type" "veclogical,integer")
+   (set_attr "length" "16")])
+
+;; 16-bit floating point absolute value
+
+(define_insn_and_split "abs<mode>2"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,?wr")
+       (abs:FP16
+        (match_operand:FP16 1 "gpc_reg_operand" "wa,wr")))
+   (clobber (match_scratch:FP16 2 "=&wa,&r"))]
+  ""
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+       (match_dup 3))
+   (set (match_dup 0)
+       (and:FP16 (match_dup 1)
+                 (not:FP16 (match_dup 2))))]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (<MODE>mode);
+
+  REAL_VALUE_TYPE dconst;
+
+  gcc_assert (real_from_string (&dconst, "-0.0") == 0);
+
+  rtx rc = const_double_from_real_value (dconst, <MODE>mode);
+
+  if (!TARGET_PREFIXED)
+    rc = force_const_mem (<MODE>mode, rc);
+
+  operands[3] = rc;
+}
+  [(set_attr "type" "veclogical,integer")
+   (set_attr "length" "16")])
+
+;; 16-bit negative floating point absolute value
+
+(define_insn_and_split "*nabs<mode>2"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,?wr")
+       (neg:FP16
+        (abs:FP16
+         (match_operand:FP16 1 "gpc_reg_operand" "wa,wr"))))
+   (clobber (match_scratch:FP16 2 "=&wa,&r"))]
+  ""
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+       (match_dup 3))
+   (set (match_dup 0)
+       (ior:FP16 (match_dup 1)
+                 (match_dup 2)))]
+{
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (<MODE>mode);
+
+  REAL_VALUE_TYPE dconst;
+
+  gcc_assert (real_from_string (&dconst, "-0.0") == 0);
+  rtx rc = const_double_from_real_value (dconst, <MODE>mode);
+
+  if (!TARGET_PREFIXED)
+    rc = force_const_mem (<MODE>mode, rc);
+
+  operands[3] = rc;
+}
+  [(set_attr "type" "veclogical,integer")
+   (set_attr "length" "16")])
+
+;; Add logical operations for 16-bit floating point types that are used
+;; for things like negate, abs, and negative abs.  Possibly in the
+;; future we might need logical operators for extracting exponents and
+;; mantissas.
+(define_expand "and<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+       (and:FP16 (match_operand:FP16 1 "gpc_reg_operand")
+                 (match_operand:FP16 2 "gpc_reg_operand")))]
+  ""
+  "")
+
+(define_expand "ior<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+        (ior:FP16 (match_operand:FP16 1 "gpc_reg_operand")
+                 (match_operand:FP16 2 "gpc_reg_operand")))]
+  ""
+  "")
+
+(define_expand "xor<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+        (xor:FP16 (match_operand:FP16 1 "gpc_reg_operand")
+                 (match_operand:FP16 2 "gpc_reg_operand")))]
+  ""
+  "")
+
+(define_expand "nor<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+       (and:FP16
+        (not:FP16 (match_operand:FP16 1 "gpc_reg_operand"))
+        (not:FP16 (match_operand:FP16 2 "gpc_reg_operand"))))]
+  ""
+  "")
+
+(define_expand "andn<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+        (and:FP16
+        (not:FP16 (match_operand:FP16 2 "gpc_reg_operand"))
+        (match_operand:FP16 1 "gpc_reg_operand")))]
+  ""
+  "")
+
+(define_expand "eqv<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+       (not:FP16
+        (xor:FP16 (match_operand:FP16 1 "gpc_reg_operand")
+                  (match_operand:FP16 2 "gpc_reg_operand"))))]
+  ""
+  "")
+
+;; Rewrite nand into canonical form
+(define_expand "nand<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+       (ior:FP16
+        (not:FP16 (match_operand:FP16 1 "gpc_reg_operand"))
+        (not:FP16 (match_operand:FP16 2 "gpc_reg_operand"))))]
+  ""
+  "")
+
+;; The canonical form is to have the negated element first, so we need to
+;; reverse arguments.
+(define_expand "iorn<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand")
+       (ior:FP16
+        (not:FP16 (match_operand:FP16 2 "gpc_reg_operand"))
+        (match_operand:FP16 1 "gpc_reg_operand")))]
+  ""
+  "")
+
+;; AND, IOR, and XOR insns.  Unlike HImode operations prefer using
+;; floating point/vector registers over GPRs.
+(define_insn "*bool<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,r")
+       (match_operator:FP16 3 "boolean_operator"
+        [(match_operand:FP16 1 "gpc_reg_operand" "wa,r")
+         (match_operand:FP16 2 "gpc_reg_operand" "wa,r")]))]
+  ""
+  "@
+   xxl%q3 %x0,%x1,%x2
+   %q3 %0,%1,%2"
+  [(set_attr "type" "veclogical,logical")])
+
+;; ANDC, IORC, and EQV insns.
+(define_insn "*boolc<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,r")
+       (match_operator:FP16 3 "boolean_operator"
+        [(not:FP16 (match_operand:FP16 2 "gpc_reg_operand" "wa,r"))
+         (match_operand:FP16 1 "gpc_reg_operand" "wa,r")]))]
+  ""
+  "@
+   xxl%q3 %x0,%x1,%x2
+   %q3 %0,%1,%2"
+  [(set_attr "type" "veclogical,logical")])
+
+(define_insn "*boolc<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,r")
+       (match_operator:FP16 3 "boolean_operator"
+        [(match_operand:FP16 1 "gpc_reg_operand" "wa,r")
+         (not:FP16 (match_operand:FP16 2 "gpc_reg_operand" "wa,r"))]))]
+  ""
+  "@
+   xxl%q3 %x0,%x1,%x2
+   %q3 %0,%1,%2"
+  [(set_attr "type" "veclogical,logical")])
+
+;; NOR and NAND insns.
+(define_insn "*boolcc<mode>3"
+  [(set (match_operand:FP16 0 "gpc_reg_operand" "=wa,r")
+       (match_operator:FP16 3 "boolean_operator"
+        [(not:FP16 (match_operand:FP16 1 "gpc_reg_operand" "wa,r"))
+         (not:FP16 (match_operand:FP16 2 "gpc_reg_operand" "wa,r"))]))]
+  ""
+  "@
+   xxl%q3 %x0,%x1,%x2
+   %q3 %0,%1,%2"
+  [(set_attr "type" "veclogical,logical")])
-- 
2.51.1



-- 
Michael Meissner, IBM
PO Box 98, Ayer, Massachusetts, USA, 01432
email: [email protected]

Reply via email to