[7/11,V2] Add BF/HF negate and absolute value operations

Message ID aV7lELDAJ_b9Lz1y@cowardly-lion.the-meissners.org
State New
Headers
Series None |

Commit Message

Michael Meissner Jan. 7, 2026, 10:58 p.m. UTC
  This is a replacement patch for patch #7 of 11 to add 16-bit floating
point support.  I discovered in testing it, that we were generating the
wrong code for absolute value of BFmode and HFmode.  In particular, due
to my misunderstanding of how the %c<n> output directive worked, the
GCC compiler was emitting XXLAND instead of XXLANDC to clear the sign
bit.

This patch adds support for (NEG x), (ABS x) , and (NEG (ABS x))
operations for HFmode and BFmode.  It also adds support for doing
logical operations (AND, IOR, XOR, NOR,  ANDN, EQV, NAND, IORN) on the
16-bit floating point.  Once the previous 6 patches have been
installed, can I apply this patch?

2026-01-07  Michael Meissner  <meissner@linux.ibm.com>

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 | 203 +++++++++++++++++++++++++++++++++++
 1 file changed, 203 insertions(+)
  

Patch

diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md
index 5af33a0fcab..4331928ee19 100644
--- a/gcc/config/rs6000/float16.md
+++ b/gcc/config/rs6000/float16.md
@@ -515,3 +515,206 @@  (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"))]
+  "TARGET_FLOAT16"
+  "#"
+  "&& 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"))]
+  "TARGET_FLOAT16"
+  "#"
+  "&& 1"
+  [(set (match_dup 2)
+	(match_dup 3))
+   (set (match_dup 0)
+	(and:FP16 (not:FP16 (match_dup 2))
+		  (match_dup 1)))]
+		  
+{
+  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"))]
+  "TARGET_FLOAT16"
+  "#"
+  "&& 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")))]
+  "TARGET_FLOAT16"
+  "")
+
+(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")))]
+  "TARGET_FLOAT16"
+  "")
+
+(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")))]
+  "TARGET_FLOAT16"
+  "")
+
+(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"))))]
+  "TARGET_FLOAT16"
+  "")
+
+(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")))]
+  "TARGET_FLOAT16"
+  "")
+
+(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"))))]
+  "TARGET_FLOAT16"
+  "")
+
+;; 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"))))]
+  "TARGET_FLOAT16"
+  "")
+
+;; 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")))]
+  "TARGET_FLOAT16"
+  "")
+
+;; 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")]))]
+  "TARGET_FLOAT16"
+  "@
+   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")]))]
+  "TARGET_FLOAT16"
+  "@
+   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"))]))]
+  "TARGET_FLOAT16"
+  "@
+   xxl%q3 %x0,%x1,%x2
+   %q3 %0,%1,%2"
+  [(set_attr "type" "veclogical,logical")])