diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 3fee2569680..b860be8bb77 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -2874,6 +2874,7 @@ expand_asm_loc (tree string, int vol, location_t locus) auto_vec input_rvec, output_rvec; auto_vec input_mode; auto_vec constraints; + auto_vec use_rvec; auto_vec 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 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) { diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h index f8cb6562096..6e44d29b433 100644 --- a/gcc/config/arm/aarch-common-protos.h +++ b/gcc/config/arm/aarch-common-protos.h @@ -155,7 +155,7 @@ struct cpu_cost_table rtx_insn *arm_md_asm_adjust (vec &outputs, vec & /*inputs*/, vec & /*input_modes*/, - vec &constraints, + vec &constraints, vec &, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t loc); diff --git a/gcc/config/arm/aarch-common.cc b/gcc/config/arm/aarch-common.cc index 5b96ff4c2e8..d68b7047c9b 100644 --- a/gcc/config/arm/aarch-common.cc +++ b/gcc/config/arm/aarch-common.cc @@ -534,7 +534,8 @@ arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer) rtx_insn * arm_md_asm_adjust (vec &outputs, vec & /*inputs*/, vec & /*input_modes*/, - vec &constraints, vec & /*clobbers*/, + vec &constraints, + vec & /*uses*/, vec & /*clobbers*/, HARD_REG_SET & /*clobbered_regs*/, location_t loc) { bool saw_asm_flag = false; diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 5cb35e8d061..5ac67c1e28b 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -328,7 +328,7 @@ static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT); static rtx_insn *thumb1_md_asm_adjust (vec &, vec &, vec &, vec &, vec &, - HARD_REG_SET &, location_t); + vec &, 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 &outputs, vec & /*inputs*/, vec & /*input_modes*/, - vec &constraints, vec & /*clobbers*/, + vec &constraints, + vec &, vec & /*clobbers*/, HARD_REG_SET & /*clobbered_regs*/, location_t /*loc*/) { for (unsigned i = 0, n = outputs.length (); i < n; ++i) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 3af9ca8d17f..c5e9ccf9663 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -15085,6 +15085,7 @@ static rtx_insn * avr_md_asm_adjust (vec &/*outputs*/, vec &/*inputs*/, vec & /*input_modes*/, vec &/*constraints*/, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { diff --git a/gcc/config/cris/cris.cc b/gcc/config/cris/cris.cc index 8b0f82e9810..7705c25ed6c 100644 --- a/gcc/config/cris/cris.cc +++ b/gcc/config/cris/cris.cc @@ -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 &, vec &, vec &, vec &, - vec &, HARD_REG_SET &, location_t); + vec &, vec &, + 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 &outputs, vec &inputs, vec & /*input_modes*/, - vec &constraints, vec &clobbers, + vec &constraints, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { /* For the time being, all asms clobber condition codes. diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 6ab3f61a8cc..7c5cab4e2c6 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -23681,8 +23681,9 @@ static void map_egpr_constraints (vec &constraints) static rtx_insn * ix86_md_asm_adjust (vec &outputs, vec & /*inputs*/, vec & /*input_modes*/, - vec &constraints, vec &clobbers, - HARD_REG_SET &clobbered_regs, location_t loc) + vec &constraints, vec &/*uses*/, + vec &clobbers, HARD_REG_SET &clobbered_regs, + location_t loc) { bool saw_asm_flag = false; diff --git a/gcc/config/mn10300/mn10300.cc b/gcc/config/mn10300/mn10300.cc index cd1de1b2d83..d56247afc08 100644 --- a/gcc/config/mn10300/mn10300.cc +++ b/gcc/config/mn10300/mn10300.cc @@ -2850,7 +2850,8 @@ mn10300_conditional_register_usage (void) static rtx_insn * mn10300_md_asm_adjust (vec & /*outputs*/, vec & /*inputs*/, vec & /*input_modes*/, - vec & /*constraints*/, vec &clobbers, + vec & /*constraints*/, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (gen_rtx_REG (CCmode, CC_REG)); diff --git a/gcc/config/nds32/nds32.cc b/gcc/config/nds32/nds32.cc index e0a73985b66..921102df51b 100644 --- a/gcc/config/nds32/nds32.cc +++ b/gcc/config/nds32/nds32.cc @@ -4200,8 +4200,8 @@ nds32_md_asm_adjust (vec &outputs ATTRIBUTE_UNUSED, vec &inputs ATTRIBUTE_UNUSED, vec &input_modes ATTRIBUTE_UNUSED, vec &constraints ATTRIBUTE_UNUSED, - vec &clobbers, HARD_REG_SET &clobbered_regs, - location_t /*loc*/) + vec &/*uses*/, vec &clobbers, + HARD_REG_SET &clobbered_regs, location_t /*loc*/) { if (!flag_inline_asm_r15) { diff --git a/gcc/config/pdp11/pdp11.cc b/gcc/config/pdp11/pdp11.cc index 78c1927f143..478297e4a58 100644 --- a/gcc/config/pdp11/pdp11.cc +++ b/gcc/config/pdp11/pdp11.cc @@ -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 &, vec &, vec &, vec &, - vec &, HARD_REG_SET &, location_t); + vec &, vec &, + 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 & /*outputs*/, vec & /*inputs*/, vec & /*input_modes*/, - vec & /*constraints*/, vec &clobbers, + vec & /*constraints*/, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (gen_rtx_REG (CCmode, CC_REGNUM)); diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 5386470f6f8..bff06f73bcf 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -3387,7 +3387,8 @@ darwin_rs6000_override_options (void) static rtx_insn * rs6000_md_asm_adjust (vec & /*outputs*/, vec & /*inputs*/, vec & /*input_modes*/, - vec & /*constraints*/, vec &clobbers, + vec & /*constraints*/, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (gen_rtx_REG (SImode, CA_REGNO)); diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 384fdb93df5..044de874590 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -17513,7 +17513,8 @@ s390_hard_fp_reg_p (rtx x) static rtx_insn * s390_md_asm_adjust (vec &outputs, vec &inputs, vec &input_modes, - vec &constraints, vec & /*clobbers*/, + vec &constraints, + vec &/*uses*/, vec &/*clobbers*/, HARD_REG_SET &clobbered_regs, location_t loc) { diff --git a/gcc/config/vax/vax.cc b/gcc/config/vax/vax.cc index 032de712946..ccaf14b27d2 100644 --- a/gcc/config/vax/vax.cc +++ b/gcc/config/vax/vax.cc @@ -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 &, vec &, vec &, vec &, - vec &, HARD_REG_SET &, location_t); + vec &, vec &, 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 &outputs ATTRIBUTE_UNUSED, vec &inputs ATTRIBUTE_UNUSED, vec &input_modes ATTRIBUTE_UNUSED, vec &constraints ATTRIBUTE_UNUSED, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { diff --git a/gcc/config/visium/visium.cc b/gcc/config/visium/visium.cc index 4a1877c2ac1..0691ea2ad13 100644 --- a/gcc/config/visium/visium.cc +++ b/gcc/config/visium/visium.cc @@ -189,7 +189,7 @@ static tree visium_build_builtin_va_list (void); static rtx_insn *visium_md_asm_adjust (vec &, vec &, vec &, vec &, vec &, - HARD_REG_SET &, location_t); + vec &, 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 & /*outputs*/, vec & /*inputs*/, vec & /*input_modes*/, - vec & /*constraints*/, vec &clobbers, + vec & /*constraints*/, + vec &/*uses*/, vec &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM)); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 1246ed12ca5..a2801ca5987 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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& @var{outputs}, vec& @var{inputs}, vec& @var{input_modes}, vec& @var{constraints}, vec& @var{clobbers}, HARD_REG_SET& @var{clobbered_regs}, location_t @var{loc}) +@deftypefn {Target Hook} {rtx_insn *} TARGET_MD_ASM_ADJUST (vec& @var{outputs}, vec& @var{inputs}, vec& @var{input_modes}, vec& @var{constraints}, vec& @var{usess}, vec& @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. diff --git a/gcc/recog.cc b/gcc/recog.cc index eaab79c25d7..ed084fa8808 100644 --- a/gcc/recog.cc +++ b/gcc/recog.cc @@ -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) diff --git a/gcc/target.def b/gcc/target.def index 4addee1ab03..b51939a4f85 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -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& outputs, vec& inputs, vec& input_modes, - vec& constraints, vec& clobbers, + vec& constraints, vec& usess, vec& clobbers, HARD_REG_SET& clobbered_regs, location_t loc), NULL)