Allow targets to add USEs to asms

Arm's SME has an array called ZA that for inline asm purposes
is effectively a form of special-purpose memory.  It doesn't
have an associated storage type and so can't be passed and
returned in normal C/C++ objects.

We'd therefore like "za" in a clobber list to mean that an inline
asm can read from and write to ZA.  (Just reading or writing
individually is unlikely to be useful, but we could add syntax
for that too if necessary.)

There is currently a TARGET_MD_ASM_ADJUST target hook that allows
targets to add clobbers to an asm instruction.  This patch
extends that to allow targets to add USEs as well.

gcc/
	* target.def (md_asm_adjust): Add a uses parameter.
	* doc/tm.texi: Regenerate.
	* cfgexpand.cc (expand_asm_loc): Update call to md_asm_adjust.
	Handle any USEs created by the target.
	(expand_asm_stmt): Likewise.
	* recog.cc (asm_noperands): Handle asms with USEs.
	(decode_asm_operands): Likewise.
	* config/arm/aarch-common-protos.h (arm_md_asm_adjust): Add uses
	parameter.
	* config/arm/aarch-common.cc (arm_md_asm_adjust): Likewise.
	* config/arm/arm.cc (thumb1_md_asm_adjust): Likewise.
	* config/avr/avr.cc (avr_md_asm_adjust): Likewise.
	* config/cris/cris.cc (cris_md_asm_adjust): Likewise.
	* config/i386/i386.cc (ix86_md_asm_adjust): Likewise.
	* config/mn10300/mn10300.cc (mn10300_md_asm_adjust): Likewise.
	* config/nds32/nds32.cc (nds32_md_asm_adjust): Likewise.
	* config/pdp11/pdp11.cc (pdp11_md_asm_adjust): Likewise.
	* config/rs6000/rs6000.cc (rs6000_md_asm_adjust): Likewise.
	* config/s390/s390.cc (s390_md_asm_adjust): Likewise.
	* config/vax/vax.cc (vax_md_asm_adjust): Likewise.
	* config/visium/visium.cc (visium_md_asm_adjust): Likewise.
This commit is contained in:
Richard Sandiford 2023-12-05 09:52:41 +00:00
parent 672fad57c1
commit 414d795d8a
17 changed files with 77 additions and 40 deletions

View file

@ -2874,6 +2874,7 @@ expand_asm_loc (tree string, int vol, location_t locus)
auto_vec<rtx> input_rvec, output_rvec;
auto_vec<machine_mode> input_mode;
auto_vec<const char *> constraints;
auto_vec<rtx> use_rvec;
auto_vec<rtx> clobber_rvec;
HARD_REG_SET clobbered_regs;
CLEAR_HARD_REG_SET (clobbered_regs);
@ -2883,16 +2884,20 @@ expand_asm_loc (tree string, int vol, location_t locus)
if (targetm.md_asm_adjust)
targetm.md_asm_adjust (output_rvec, input_rvec, input_mode,
constraints, clobber_rvec, clobbered_regs,
locus);
constraints, use_rvec, clobber_rvec,
clobbered_regs, locus);
asm_op = body;
nclobbers = clobber_rvec.length ();
body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + nclobbers));
auto nuses = use_rvec.length ();
body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + nuses + nclobbers));
XVECEXP (body, 0, 0) = asm_op;
for (i = 0; i < nclobbers; i++)
XVECEXP (body, 0, i + 1) = gen_rtx_CLOBBER (VOIDmode, clobber_rvec[i]);
i = 0;
XVECEXP (body, 0, i++) = asm_op;
for (rtx use : use_rvec)
XVECEXP (body, 0, i++) = gen_rtx_USE (VOIDmode, use);
for (rtx clobber : clobber_rvec)
XVECEXP (body, 0, i++) = gen_rtx_CLOBBER (VOIDmode, clobber);
}
emit_insn (body);
@ -3444,11 +3449,12 @@ expand_asm_stmt (gasm *stmt)
maintaining source-level compatibility means automatically clobbering
the flags register. */
rtx_insn *after_md_seq = NULL;
auto_vec<rtx> use_rvec;
if (targetm.md_asm_adjust)
after_md_seq
= targetm.md_asm_adjust (output_rvec, input_rvec, input_mode,
constraints, clobber_rvec, clobbered_regs,
locus);
constraints, use_rvec, clobber_rvec,
clobbered_regs, locus);
/* Do not allow the hook to change the output and input count,
lest it mess up the operand numbering. */
@ -3456,7 +3462,8 @@ expand_asm_stmt (gasm *stmt)
gcc_assert (input_rvec.length() == ninputs);
gcc_assert (constraints.length() == noutputs + ninputs);
/* But it certainly can adjust the clobbers. */
/* But it certainly can adjust the uses and clobbers. */
unsigned nuses = use_rvec.length ();
unsigned nclobbers = clobber_rvec.length ();
/* Third pass checks for easy conflicts. */
@ -3528,7 +3535,7 @@ expand_asm_stmt (gasm *stmt)
ARGVEC CONSTRAINTS OPNAMES))
If there is more than one, put them inside a PARALLEL. */
if (noutputs == 0 && nclobbers == 0)
if (noutputs == 0 && nuses == 0 && nclobbers == 0)
{
/* No output operands: put in a raw ASM_OPERANDS rtx. */
if (nlabels > 0)
@ -3536,7 +3543,7 @@ expand_asm_stmt (gasm *stmt)
else
emit_insn (body);
}
else if (noutputs == 1 && nclobbers == 0)
else if (noutputs == 1 && nuses == 0 && nclobbers == 0)
{
ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
if (nlabels > 0)
@ -3552,7 +3559,8 @@ expand_asm_stmt (gasm *stmt)
if (num == 0)
num = 1;
body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num + nclobbers));
body = gen_rtx_PARALLEL (VOIDmode,
rtvec_alloc (num + nuses + nclobbers));
/* For each output operand, store a SET. */
for (i = 0; i < noutputs; ++i)
@ -3579,6 +3587,11 @@ expand_asm_stmt (gasm *stmt)
if (i == 0)
XVECEXP (body, 0, i++) = obody;
/* Add the uses specified by the target hook. No checking should
be needed since this doesn't come directly from user code. */
for (rtx use : use_rvec)
XVECEXP (body, 0, i++) = gen_rtx_USE (VOIDmode, use);
/* Store (clobber REG) for each clobbered register specified. */
for (unsigned j = 0; j < nclobbers; ++j)
{

View file

@ -155,7 +155,7 @@ struct cpu_cost_table
rtx_insn *arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &constraints,
vec<const char *> &constraints, vec<rtx> &,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs,
location_t loc);

View file

@ -534,7 +534,8 @@ arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
rtx_insn *
arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &constraints, vec<rtx> & /*clobbers*/,
vec<const char *> &constraints,
vec<rtx> & /*uses*/, vec<rtx> & /*clobbers*/,
HARD_REG_SET & /*clobbered_regs*/, location_t loc)
{
bool saw_asm_flag = false;

View file

@ -328,7 +328,7 @@ static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT);
static rtx_insn *thumb1_md_asm_adjust (vec<rtx> &, vec<rtx> &,
vec<machine_mode> &,
vec<const char *> &, vec<rtx> &,
HARD_REG_SET &, location_t);
vec<rtx> &, HARD_REG_SET &, location_t);
static const char *arm_identify_fpu_from_isa (sbitmap);
/* Table of machine attributes. */
@ -34646,7 +34646,8 @@ arm_stack_protect_guard (void)
rtx_insn *
thumb1_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &constraints, vec<rtx> & /*clobbers*/,
vec<const char *> &constraints,
vec<rtx> &, vec<rtx> & /*clobbers*/,
HARD_REG_SET & /*clobbered_regs*/, location_t /*loc*/)
{
for (unsigned i = 0, n = outputs.length (); i < n; ++i)

View file

@ -15085,6 +15085,7 @@ static rtx_insn *
avr_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &/*constraints*/,
vec<rtx> &/*uses*/,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs,
location_t /*loc*/)
{

View file

@ -152,7 +152,8 @@ static void cris_function_arg_advance (cumulative_args_t,
const function_arg_info &);
static rtx_insn *cris_md_asm_adjust (vec<rtx> &, vec<rtx> &,
vec<machine_mode> &, vec<const char *> &,
vec<rtx> &, HARD_REG_SET &, location_t);
vec<rtx> &, vec<rtx> &,
HARD_REG_SET &, location_t);
static void cris_option_override (void);
@ -3646,7 +3647,8 @@ cris_function_arg_advance (cumulative_args_t ca_v,
static rtx_insn *
cris_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &constraints, vec<rtx> &clobbers,
vec<const char *> &constraints,
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
/* For the time being, all asms clobber condition codes.

View file

@ -23681,8 +23681,9 @@ static void map_egpr_constraints (vec<const char *> &constraints)
static rtx_insn *
ix86_md_asm_adjust (vec<rtx> &outputs, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> &constraints, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t loc)
vec<const char *> &constraints, vec<rtx> &/*uses*/,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs,
location_t loc)
{
bool saw_asm_flag = false;

View file

@ -2850,7 +2850,8 @@ mn10300_conditional_register_usage (void)
static rtx_insn *
mn10300_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
vec<const char *> & /*constraints*/,
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
clobbers.safe_push (gen_rtx_REG (CCmode, CC_REG));

View file

@ -4200,8 +4200,8 @@ nds32_md_asm_adjust (vec<rtx> &outputs ATTRIBUTE_UNUSED,
vec<rtx> &inputs ATTRIBUTE_UNUSED,
vec<machine_mode> &input_modes ATTRIBUTE_UNUSED,
vec<const char *> &constraints ATTRIBUTE_UNUSED,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs,
location_t /*loc*/)
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
if (!flag_inline_asm_r15)
{

View file

@ -155,7 +155,8 @@ static int pdp11_addr_cost (rtx, machine_mode, addr_space_t, bool);
static int pdp11_insn_cost (rtx_insn *insn, bool speed);
static rtx_insn *pdp11_md_asm_adjust (vec<rtx> &, vec<rtx> &,
vec<machine_mode> &, vec<const char *> &,
vec<rtx> &, HARD_REG_SET &, location_t);
vec<rtx> &, vec<rtx> &,
HARD_REG_SET &, location_t);
static bool pdp11_return_in_memory (const_tree, const_tree);
static rtx pdp11_function_value (const_tree, const_tree, bool);
static rtx pdp11_libcall_value (machine_mode, const_rtx);
@ -2137,7 +2138,8 @@ pdp11_cmp_length (rtx *operands, int words)
static rtx_insn *
pdp11_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
vec<const char *> & /*constraints*/,
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
clobbers.safe_push (gen_rtx_REG (CCmode, CC_REGNUM));

View file

@ -3387,7 +3387,8 @@ darwin_rs6000_override_options (void)
static rtx_insn *
rs6000_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
vec<const char *> & /*constraints*/,
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
clobbers.safe_push (gen_rtx_REG (SImode, CA_REGNO));

View file

@ -17513,7 +17513,8 @@ s390_hard_fp_reg_p (rtx x)
static rtx_insn *
s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
vec<machine_mode> &input_modes,
vec<const char *> &constraints, vec<rtx> & /*clobbers*/,
vec<const char *> &constraints,
vec<rtx> &/*uses*/, vec<rtx> &/*clobbers*/,
HARD_REG_SET &clobbered_regs, location_t loc)
{

View file

@ -58,7 +58,8 @@ static bool vax_rtx_costs (rtx, machine_mode, int, int, int *, bool);
static machine_mode vax_cc_modes_compatible (machine_mode, machine_mode);
static rtx_insn *vax_md_asm_adjust (vec<rtx> &, vec<rtx> &,
vec<machine_mode> &, vec<const char *> &,
vec<rtx> &, HARD_REG_SET &, location_t);
vec<rtx> &, vec<rtx> &, HARD_REG_SET &,
location_t);
static rtx vax_function_arg (cumulative_args_t, const function_arg_info &);
static void vax_function_arg_advance (cumulative_args_t,
const function_arg_info &);
@ -1180,6 +1181,7 @@ vax_md_asm_adjust (vec<rtx> &outputs ATTRIBUTE_UNUSED,
vec<rtx> &inputs ATTRIBUTE_UNUSED,
vec<machine_mode> &input_modes ATTRIBUTE_UNUSED,
vec<const char *> &constraints ATTRIBUTE_UNUSED,
vec<rtx> &/*uses*/,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs,
location_t /*loc*/)
{

View file

@ -189,7 +189,7 @@ static tree visium_build_builtin_va_list (void);
static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
vec<machine_mode> &,
vec<const char *> &, vec<rtx> &,
HARD_REG_SET &, location_t);
vec<rtx> &, HARD_REG_SET &, location_t);
static bool visium_legitimate_constant_p (machine_mode, rtx);
@ -794,7 +794,8 @@ visium_conditional_register_usage (void)
static rtx_insn *
visium_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
vec<machine_mode> & /*input_modes*/,
vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
vec<const char *> & /*constraints*/,
vec<rtx> &/*uses*/, vec<rtx> &clobbers,
HARD_REG_SET &clobbered_regs, location_t /*loc*/)
{
clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));

View file

@ -11821,10 +11821,11 @@ from shared libraries (DLLs).
You need not define this macro if it would always evaluate to zero.
@end defmac
@deftypefn {Target Hook} {rtx_insn *} TARGET_MD_ASM_ADJUST (vec<rtx>& @var{outputs}, vec<rtx>& @var{inputs}, vec<machine_mode>& @var{input_modes}, vec<const char *>& @var{constraints}, vec<rtx>& @var{clobbers}, HARD_REG_SET& @var{clobbered_regs}, location_t @var{loc})
@deftypefn {Target Hook} {rtx_insn *} TARGET_MD_ASM_ADJUST (vec<rtx>& @var{outputs}, vec<rtx>& @var{inputs}, vec<machine_mode>& @var{input_modes}, vec<const char *>& @var{constraints}, vec<rtx>& @var{usess}, vec<rtx>& @var{clobbers}, HARD_REG_SET& @var{clobbered_regs}, location_t @var{loc})
This target hook may add @dfn{clobbers} to @var{clobbers} and
@var{clobbered_regs} for any hard regs the port wishes to automatically
clobber for an asm. The @var{outputs} and @var{inputs} may be inspected
clobber for an asm. It can also add hard registers that are used by the
asm to @var{uses}. The @var{outputs} and @var{inputs} may be inspected
to avoid clobbering a register that is already used by the asm. @var{loc}
is the source location of the asm.

View file

@ -1990,13 +1990,17 @@ asm_noperands (const_rtx body)
{
/* Multiple output operands, or 1 output plus some clobbers:
body is
[(set OUTPUT (asm_operands ...))... (clobber (reg ...))...]. */
/* Count backwards through CLOBBERs to determine number of SETs. */
[(set OUTPUT (asm_operands ...))...
(use (reg ...))...
(clobber (reg ...))...]. */
/* Count backwards through USEs and CLOBBERs to determine
number of SETs. */
for (i = XVECLEN (body, 0); i > 0; i--)
{
if (GET_CODE (XVECEXP (body, 0, i - 1)) == SET)
break;
if (GET_CODE (XVECEXP (body, 0, i - 1)) != CLOBBER)
if (GET_CODE (XVECEXP (body, 0, i - 1)) != USE
&& GET_CODE (XVECEXP (body, 0, i - 1)) != CLOBBER)
return -1;
}
@ -2023,10 +2027,13 @@ asm_noperands (const_rtx body)
else
{
/* 0 outputs, but some clobbers:
body is [(asm_operands ...) (clobber (reg ...))...]. */
body is [(asm_operands ...)
(use (reg ...))...
(clobber (reg ...))...]. */
/* Make sure all the other parallel things really are clobbers. */
for (i = XVECLEN (body, 0) - 1; i > 0; i--)
if (GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
if (GET_CODE (XVECEXP (body, 0, i)) != USE
&& GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
return -1;
}
}
@ -2093,7 +2100,8 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
the SETs. Their constraints are in the ASM_OPERANDS itself. */
for (i = 0; i < nparallel; i++)
{
if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
if (GET_CODE (XVECEXP (body, 0, i)) == USE
|| GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
break; /* Past last SET */
gcc_assert (GET_CODE (XVECEXP (body, 0, i)) == SET);
if (operands)

View file

@ -4342,7 +4342,8 @@ DEFHOOK
(md_asm_adjust,
"This target hook may add @dfn{clobbers} to @var{clobbers} and\n\
@var{clobbered_regs} for any hard regs the port wishes to automatically\n\
clobber for an asm. The @var{outputs} and @var{inputs} may be inspected\n\
clobber for an asm. It can also add hard registers that are used by the\n\
asm to @var{uses}. The @var{outputs} and @var{inputs} may be inspected\n\
to avoid clobbering a register that is already used by the asm. @var{loc}\n\
is the source location of the asm.\n\
\n\
@ -4353,7 +4354,7 @@ changes to @var{inputs} must be accompanied by the corresponding changes\n\
to @var{input_modes}.",
rtx_insn *,
(vec<rtx>& outputs, vec<rtx>& inputs, vec<machine_mode>& input_modes,
vec<const char *>& constraints, vec<rtx>& clobbers,
vec<const char *>& constraints, vec<rtx>& usess, vec<rtx>& clobbers,
HARD_REG_SET& clobbered_regs, location_t loc),
NULL)