On 7/12/24 14:52, Jeff Law wrote:
>> +(define_insn "*fclass<ANYF:mode><X:mode>"
>> +  [(set (match_operand:X         0 "register_operand" "=r")
>> +    (unspec [(match_operand:ANYF 1 "register_operand" " f")]
>> +               UNSPEC_FCLASS))]
>> +  "TARGET_HARD_FLOAT"
>> +  "fclass.<fmt>\t%0,%1";
>> +  [(set_attr "type" "fcmp")
>> +   (set_attr "mode" "<UNITMODE>")])
>> +
>> +;; Implementation note:
>> +;;  Indirection via the expander needed due to md syntax limitations.
>> +;;  define_insn needs tighter mode check (X for operand0) requiring <X:mode>
>> +;;  in name.  This forces callers like isfinite to specify mode but can't 
>> due
>> +;;  to their own standard pattern name requirement.  The additional expander
>> +;;  with matching RTL template (but elided mode check) allows callers to use
>> +;;  expander's name with actual asm coming from stricter define_insn.
>> +
>> +(define_expand "fclass<ANYF:mode>"
>> +  [(set (match_operand                   0 "register_operand" "=r")
>> +    (unspec [(match_operand:ANYF 1 "register_operand" " f")]
>> +               UNSPEC_FCLASS))]
>> +  "TARGET_HARD_FLOAT")
> Note that for fclass, which isn't a standard pattern name, you have 
> additional text in the same -- say for example a mode.  It's just those 
> standard names defined in md.texi where we have naming restrictions.
>
> The net is you can avoid the fclass expander entirely.   So you can drop 
> the '*' in the fclass pattern. 

Note to myself (after verifying):
 - dropping of '*' is also needed to be able to call them explicitly
from other expanders.
 - '*' prefix patterns are purely for internal recog()

> Then call it as
> gen_fclass<ANYF:mode>di or gen_fclass<ANYF:mode>si in the is* expanders.

Meaning this requires callers to be

  if (TARGET_64BIT)
    emit_insn (gen_fclass<ANYF:mode>di (t, operands[1]));
  else
    emit_insn (gen_fclass<ANYF:mode>si (t, operands[1]));

since they can't do the following due to their own Std pattern name
reqmt lest redefinition issue.

  emit_insn (gen_fclass<ANYF:mode><X:mode> (t, operands[1]));

>
>> +   /* Allow SI for rv32/rv64 and DI for rv64
>> +      Explicit mode check (vs. specfying modes in RTL template 
>> match_operand)
>> +      due to syntax limitations.
>> +       - Specifying X would cause multiple definitions
>> +       - And to disambuguate that requires adding <X:mode> to name which
>> +     no longer matches the "standard pattern name".  */
>> +  if (GET_MODE (operands[0]) != SImode
>> +      && GET_MODE (operands[0]) != word_mode)
>> +    FAIL;
>> +
>> +  rtx t = gen_reg_rtx (word_mode);
>> +  rtx t_op0 = gen_reg_rtx (word_mode);
>> +
>> +  emit_insn (gen_fclass<ANYF:mode> (t, operands[1]));
>> +  riscv_emit_binary (AND, t, t, GEN_INT (0x7e));
>> +  rtx cmp = gen_rtx_NE (word_mode, t, const0_rtx);
>> +  emit_insn (gen_cstore<mode>4 (t_op0, cmp, t, const0_rtx));
>> +
>> +  if (TARGET_64BIT)
>> +    {
>> +      t_op0 = gen_lowpart (SImode, t_op0);
>> +      SUBREG_PROMOTED_VAR_P (t_op0) = 1;
>> +      SUBREG_PROMOTED_SET (t_op0, SRP_SIGNED);
>> +    }
>> +
>> +  emit_move_insn (operands[0], t_op0);
>> +  DONE;
>> +})
> So this is repeated nearly verbatim in all 3 is* expanders.  Seems ripe 
> for refactoring where you pass in the magic constant (which is all that 
> seems to change across those code fragments).

Yeah I should have thought about it myself. The prior tri-modal return
was different but now clearly this can all be combined.
I was hoping to use int iterators, but it seems this will have be a
helper in riscv.cc which is called from 3 explicit expanders.

> Hate to ask for another spin, but the refactoring seems like its worth 
> doing to avoid the duplication.  

Not a problem, I'll eventually get the md syntax :-)

> And if we're going to spin again, might 
> as well drop the fclass expander that we really don't need.

Of course.

-Vineet

Reply via email to