On 7/9/24 8:35 PM, Xi Ruoyao wrote:
On Mon, 2024-07-08 at 15:03 -0600, Jeff Law wrote:
So I would use tmp (or another word_mode pseudo register) for the
destination of that emit_insn. Then something like:
t = gen_lowpart (SImode, tmp);
SUBREG_PROMOTED_VAR_P (tmp) = 1;
SUBREG_PROMOTED_SET (tmp, SRP_SIGNED);
emit_move_insn (operands[0], tmp);
To the output into operands[0] with enough magic to allow us to
potentially remove a subsequent sign extension.
I'd already tried this trick for LoongArch:
(define_int_attr fclass_optab
[(68 "isinf")
(136 "isnormal")
(952 "isfinite")])
(define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
[(match_operand:SI 0 "register_operand" "=r")
(match_operand:ANYF 1 "register_operand" " f")
(const_int FCLASS_MASK)]
"TARGET_HARD_FLOAT"
{
rtx ft0 = gen_reg_rtx (SImode);
rtx t0 = gen_reg_rtx (word_mode);
rtx mask = GEN_INT (<FCLASS_MASK>);
emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
if (TARGET_64BIT)
emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
else
emit_move_insn (t0, ft0);
emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
if (TARGET_64BIT)
{
t0 = lowpart_subreg (SImode, t0, DImode);
SUBREG_PROMOTED_VAR_P (t0) = 1;
SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
}
emit_move_insn (operands[0], t0);
DONE;
})
But for a test case:
__attribute__ ((noipa)) int
test_fclass_f (float f)
{
return __builtin_isinf (f)
| __builtin_isnormal (f) << 1
| __builtin_isfinite (f) << 2;
}
I still get:
test_fclass_f:
fclass.s $f0,$f0
movfr2gr.s $r4,$f0
andi $r12,$r4,136
andi $r13,$r4,952
sltu $r12,$r0,$r12
sltu $r13,$r0,$r13
slli.w $r13,$r13,2
andi $r4,$r4,68
slli.w $r12,$r12,1
or $r12,$r12,$r13
sltu $r4,$r0,$r4
or $r4,$r4,$r12
andi $r4,$r4,7 # <==== Why we need this?!
You'll need to debug it. It's not a zero or sign extension, so it's not
going to be impacted by the SUBREG_PROMOTED stuff.
Jeff