There were scalar ctz/clz instructions, but the vector counterparts were
missing.

gcc/ChangeLog:

        * config/gcn/gcn-opts.h (TARGET_RDNA3_PLUS): New.
        * config/gcn/gcn-valu.md (<expander><mode>2<exec>): New.
        (<expander><mode>2): New.
        (<expander><mode>2_natural): New.
        * config/gcn/gcn.md (rnda): Add n3 and 3p values.
        (enabled): Handle rdna n3 and 3p.
        (mnemonic): Add clz and ctz.
        (rdna_mnemonic): New code attribute.
---
 gcc/config/gcn/gcn-opts.h  |  1 +
 gcc/config/gcn/gcn-valu.md | 74 ++++++++++++++++++++++++++++++++++++++
 gcc/config/gcn/gcn.md      | 19 ++++++++--
 3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/gcc/config/gcn/gcn-opts.h b/gcc/config/gcn/gcn-opts.h
index d771e788e31..b983d59343b 100644
--- a/gcc/config/gcn/gcn-opts.h
+++ b/gcc/config/gcn/gcn-opts.h
@@ -47,6 +47,7 @@ extern enum gcn_isa {
 #define TARGET_RDNA2 (gcn_isa == ISA_RDNA2)
 #define TARGET_RDNA2_PLUS (gcn_isa >= ISA_RDNA2 && gcn_isa < ISA_CDNA1)
 #define TARGET_RDNA3 (gcn_isa == ISA_RDNA3)
+#define TARGET_RDNA3_PLUS (gcn_isa >= ISA_RDNA3 && gcn_isa < ISA_CDNA1)
 
 
 #define TARGET_PACKED_WORK_ITEMS (TARGET_CDNA2_PLUS || TARGET_RDNA3)
diff --git a/gcc/config/gcn/gcn-valu.md b/gcc/config/gcn/gcn-valu.md
index edd5bf1f1d2..1dd14ec2a4c 100644
--- a/gcc/config/gcn/gcn-valu.md
+++ b/gcc/config/gcn/gcn-valu.md
@@ -2733,6 +2733,19 @@ (define_insn "<expander><mode>2<exec>"
   [(set_attr "type" "vop1")
    (set_attr "length" "8")])
 
+(define_insn "<expander><mode>2<exec>"
+  [(set (match_operand:V_SI 0 "gcn_valu_dst_operand")
+       (countzeros:V_SI
+         (match_operand:V_SI 1 "gcn_valu_src0_operand")))]
+  ""
+  {@ [cons: =0,1 ;attrs: length,rdna]
+  [v,vSv;4,n3] v_<mnemonic>0\t%0, %1
+  [v,B  ;8,n3] ^
+  [v,vSv;4,3p] v_<rdna_mnemonic>0\t%0, %1
+  [v,B  ;8,3p] ^
+  }
+  [(set_attr "type" "vop1")])
+
 (define_insn "<expander><mode>3<exec>"
   [(set (match_operand:V_INT_1REG 0 "gcn_valu_dst_operand"      "=  v,RD")
        (bitop:V_INT_1REG
@@ -2995,6 +3008,67 @@ (define_insn_and_split "<expander><mode>3_exec"
   }
   [(set_attr "type" "mult")])
 
+;; }}}
+;; {{{ ALU VnDImode
+
+(define_expand "<expander><mode>2"
+  [(match_operand:V_DI 0 "register_operand")
+   (countzeros:V_DI)
+   (match_operand:V_DI 1 "gcn_alu_operand")]
+  ""
+  {
+    rtx tmp = gen_reg_rtx (<VnSI>mode);
+    emit_insn (gen_<expander><mode>2_natural (tmp, operands[1]));
+    emit_insn (gen_zero_extend<vnsi><mode>2 (operands[0], tmp));
+    DONE;
+  })
+
+;; The ctz/clz named patterns require operand[0] to match operand[1], for
+;; vectors only.  This pattern provides a counterpart for the scalar insn,
+;; but cannot be the named pattern without an output conversion.
+(define_insn_and_split "<expander><mode>2_natural"
+  [(set (match_operand:<VnSI> 0 "register_operand"  "=&v")
+       (truncate:<VnSI>
+         (countzeros:V_DI
+           (match_operand:V_DI 1 "gcn_alu_operand" "v"))))
+   (clobber (match_scratch:<VnSI> 2 "=&v"))
+   (clobber (match_scratch:DI 3 "=&cV"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    enum {clz = 0, ctz = 1} op = <expander>;
+
+    /* "far/near" is "lo/hi" for clz, and "hi/lo" for ctz.  */
+    rtx src_far = gcn_operand_part (<MODE>mode, operands[1], op);
+    rtx src_near = gcn_operand_part (<MODE>mode, operands[1], !op);
+    rtx res_far = operands[op ? 0 : 2];
+    rtx res_near = operands[op ? 2 : 0];
+    rtx vcc = operands[3];
+
+    /* Count the parts.  */
+    emit_insn (gen_<expander><vnsi>2 (res_far, src_far));
+    emit_insn (gen_<expander><vnsi>2 (res_near, src_near));
+
+    /* Clamp the far-part to 32, to allow for the -1 result on all zeros.  */
+    emit_insn (gen_umin<vnsi>3 (res_far, res_far,
+                               gcn_vec_constant (<VnSI>mode, 32)));
+
+    /* Add 32 to the clamped far-part; we won't use this unless near-part is
+       all zeroes.  */
+    emit_insn (gen_add<vnsi>3 (res_far, res_far,
+                              gcn_vec_constant (<VnSI>mode, 32)));
+
+    /* Select which result is correct.  */
+    emit_insn (gen_vec_cmp<vnsi>di (vcc, gen_rtx_NE (VOIDmode, 0, 0),
+                                   gcn_vec_constant (<VnSI>mode, 0),
+                                   src_near));
+    emit_insn (gen_vcond_mask_<vnsi>di (operands[0], res_near, res_far, vcc));
+    DONE;
+  }
+  [(set_attr "type" "vmult")])
+
 ;; }}}
 ;; {{{ Int unops
 
diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md
index f95e7e555c9..76eeb67cb0b 100644
--- a/gcc/config/gcn/gcn.md
+++ b/gcc/config/gcn/gcn.md
@@ -287,17 +287,24 @@ (define_attr "length" ""
 ; Disable alternatives that only apply to specific ISA variants.
 
 (define_attr "cdna" "any,cdna2" (const_string "any"))
-(define_attr "rdna" "any,no,yes" (const_string "any"))
+(define_attr "rdna" "any,no,yes,n3,3p" (const_string "any"))
 
 (define_attr "xnack" "na,off,on" (const_string "na"))
 
 (define_attr "enabled" ""
-  (cond [(and (eq_attr "rdna" "no")
+  (cond [
+        (and (eq_attr "rdna" "no")
              (ne (symbol_ref "TARGET_RDNA2_PLUS") (const_int 0)))
           (const_int 0)
         (and (eq_attr "rdna" "yes")
              (eq (symbol_ref "TARGET_RDNA2_PLUS") (const_int 0)))
           (const_int 0)
+        (and (eq_attr "rdna" "n3")
+             (ne (symbol_ref "TARGET_RDNA3_PLUS") (const_int 0)))
+          (const_int 0)
+        (and (eq_attr "rdna" "3p")
+             (eq (symbol_ref "TARGET_RDNA3_PLUS") (const_int 0)))
+          (const_int 0)
         (and (eq_attr "cdna" "cdna2")
              (eq (symbol_ref "TARGET_CDNA2_PLUS") (const_int 0)))
           (const_int 0)
@@ -371,7 +378,13 @@ (define_code_attr mnemonic
    (umin "min%u")
    (umax "max%u")
    (not "not%B")
-   (popcount "bcnt_u32%b")])
+   (popcount "bcnt_u32%b")
+   (clz "ffbh%u")
+   (ctz "ffbl%b")])
+
+(define_code_attr rdna_mnemonic
+  [(clz "clz_i32%u")
+   (ctz "ctz_i32%b")])
 
 (define_code_attr bare_mnemonic
   [(plus "add")
-- 
2.54.0

Reply via email to