Implement hard register constraints of the form {regname} where regname
must be a valid register name for the target. Such constraints may be
used in asm statements as a replacement for register asm and in machine
descriptions.
---
gcc/config/cris/cris.cc | 6 +-
gcc/config/i386/i386.cc | 6 +
gcc/config/s390/s390.cc | 6 +-
gcc/doc/extend.texi | 178 ++++++++++++++++++
gcc/doc/md.texi | 6 +
gcc/function.cc | 116 ++++++++++++
gcc/genoutput.cc | 14 ++
gcc/genpreds.cc | 4 +-
gcc/ira.cc | 79 +++++++-
gcc/lra-constraints.cc | 13 ++
gcc/recog.cc | 11 +-
gcc/stmt.cc | 39 ++++
gcc/stmt.h | 1 +
gcc/testsuite/gcc.dg/asm-hard-reg-1.c | 85 +++++++++
gcc/testsuite/gcc.dg/asm-hard-reg-2.c | 33 ++++
gcc/testsuite/gcc.dg/asm-hard-reg-3.c | 25 +++
gcc/testsuite/gcc.dg/asm-hard-reg-4.c | 50 +++++
gcc/testsuite/gcc.dg/asm-hard-reg-5.c | 36 ++++
gcc/testsuite/gcc.dg/asm-hard-reg-6.c | 60 ++++++
gcc/testsuite/gcc.dg/asm-hard-reg-7.c | 41 ++++
gcc/testsuite/gcc.dg/asm-hard-reg-8.c | 49 +++++
.../gcc.target/aarch64/asm-hard-reg-1.c | 55 ++++++
.../gcc.target/i386/asm-hard-reg-1.c | 115 +++++++++++
.../gcc.target/s390/asm-hard-reg-1.c | 103 ++++++++++
.../gcc.target/s390/asm-hard-reg-2.c | 43 +++++
.../gcc.target/s390/asm-hard-reg-3.c | 42 +++++
.../gcc.target/s390/asm-hard-reg-4.c | 6 +
.../gcc.target/s390/asm-hard-reg-5.c | 6 +
.../gcc.target/s390/asm-hard-reg-6.c | 152 +++++++++++++++
.../gcc.target/s390/asm-hard-reg-longdouble.h | 18 ++
30 files changed, 1391 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-1.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-2.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-3.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-4.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-5.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-6.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-7.c
create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-8.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c
create mode 100644 gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h
diff --git a/gcc/ira.cc b/gcc/ira.cc
index 885239d1b43..c32d4ceab88 100644
--- a/gcc/ira.cc
+++ b/gcc/ira.cc
@@ -2113,6 +2113,82 @@ ira_get_dup_out_num (int op_num, alternative_mask alts,
+/* Return true if a replacement of SRC by DEST does not lead to unsatisfiable
+ asm. Thus, a replacement is valid if and only if SRC and DEST are not
+ constrained in asm inputs of a single asm statement. See
+ match_asm_constraints_2() for more details. TODO: As in
+ match_asm_constraints_2() consider alternatives more precisely. */
+
+static bool
+valid_replacement_for_asm_input_p_1 (const_rtx asmops, const_rtx src,
const_rtx dest)
+{
+ int ninputs = ASM_OPERANDS_INPUT_LENGTH (asmops);
+ rtvec inputs = ASM_OPERANDS_INPUT_VEC (asmops);
+ for (int i = 0; i < ninputs; ++i)
+ {
+ rtx input_src = RTVEC_ELT (inputs, i);
+ const char *constraint_src
+ = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, i);
+ if (rtx_equal_p (input_src, src)
+ && strchr (constraint_src, '{') != nullptr)
+ for (int j = 0; j < ninputs; ++j)
+ {
+ rtx input_dest = RTVEC_ELT (inputs, j);
+ const char *constraint_dest
+ = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, j);
+ if (rtx_equal_p (input_dest, dest)
+ && strchr (constraint_dest, '{') != nullptr)
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+valid_replacement_for_asm_input_p (const_rtx src, const_rtx dest)
+{
+ /* Bail out early if there is no asm statement. */
+ if (!crtl->has_asm_statement)
+ return true;
+ for (df_ref use = DF_REG_USE_CHAIN (REGNO (src));
+ use;
+ use = DF_REF_NEXT_REG (use))
+ {
+ struct df_insn_info *use_info = DF_REF_INSN_INFO (use);
+ /* Only check real uses, not artificial ones. */
+ if (use_info)
+ {
+ rtx_insn *insn = DF_REF_INSN (use);
+ rtx pat = PATTERN (insn);
+ if (asm_noperands (pat) <= 0)
+ continue;
+ if (GET_CODE (pat) == SET)
+ {
+ if (!valid_replacement_for_asm_input_p_1 (SET_SRC (pat), src,
dest))
+ return false;
+ }
+ else if (GET_CODE (pat) == PARALLEL)
+ for (int i = 0, len = XVECLEN (pat, 0); i < len; ++i)
+ {
+ rtx asmops = XVECEXP (pat, 0, i);
+ if (GET_CODE (asmops) == SET)
+ asmops = SET_SRC (asmops);
+ if (GET_CODE (asmops) == ASM_OPERANDS
+ && !valid_replacement_for_asm_input_p_1 (asmops, src, dest))
+ return false;
+ }
+ else if (GET_CODE (pat) == ASM_OPERANDS)
+ {
+ if (!valid_replacement_for_asm_input_p_1 (pat, src, dest))
+ return false;
+ }
+ else
+ gcc_unreachable ();
+ }
+ }
+ return true;
+}
+
/* Search forward to see if the source register of a copy insn dies
before either it or the destination register is modified, but don't
scan past the end of the basic block. If so, we can replace the
@@ -2162,7 +2238,8 @@ decrease_live_ranges_number (void)
auto-inc memory reference, so we must disallow this
optimization on them. */
|| sregno == STACK_POINTER_REGNUM
- || dregno == STACK_POINTER_REGNUM)
+ || dregno == STACK_POINTER_REGNUM
+ || !valid_replacement_for_asm_input_p (src, dest))
continue;
dest_death = NULL_RTX;
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 7dbc7fe1e00..689a12b2c71 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -114,6 +114,7 @@
#include "target.h"
#include "rtl.h"
#include "tree.h"
+#include "stmt.h"
#include "predict.h"
#include "df.h"
#include "memmodel.h"
@@ -2175,6 +2176,7 @@ process_alt_operands (int only_alternative)
bool costly_p;
enum reg_class cl;
const HARD_REG_SET *cl_filter;
+ HARD_REG_SET hard_reg_constraint;
/* Calculate some data common for all alternatives to speed up the
function. */
@@ -2551,6 +2553,17 @@ process_alt_operands (int only_alternative)
cl_filter = nullptr;
goto reg;
+ case '{':
+ {
+ int regno = decode_hard_reg_constraint (p);
+ gcc_assert (regno >= 0);
+ cl = REGNO_REG_CLASS (regno);
+ CLEAR_HARD_REG_SET (hard_reg_constraint);
+ SET_HARD_REG_BIT (hard_reg_constraint, regno);
+ cl_filter = &hard_reg_constraint;
+ goto reg;
+ }
+
default:
cn = lookup_constraint (p);
switch (get_constraint_type (cn))