https://gcc.gnu.org/g:f311d59c4d45f5042029647c88966e2e48330adf
commit r17-4275-gf311d59c4d45f5042029647c88966e2e48330adf Author: Stefan Schulze Frielinghaus <[email protected]> Date: Wed Sep 16 08:27:33 2026 +0200 ira: Treat hard register constraints similarly as single reg class constraints Treat a hard register constraint the same way as a constraint associated a single register class for process_single_reg_class_operands(). gcc/ChangeLog: * ira-lives.cc (single_reg_class): Compute regno in case of single reg class constraint or hard register constraint, and rename to ... (single_reg_class_regno): ... this. (single_reg_operand_class): Similarly as before and rename to ... (single_reg_operand_class_regno): ... this. (process_single_reg_class_operands): Utilize single_reg_operand_class_regno() and deal with regnos directly instead of single reg classes. (process_single_reg_class_operands): Rename to ... (process_single_reg_constrained_operands): ... this. (process_bb_node_lives): Refer to renamed function. gcc/testsuite/ChangeLog: * gcc.dg/asm-hard-reg-6.c: This patch would result in only one reload for alternative 1 in test_reg_reg which changes costing which in turn leads to choosing alternative 1 for which we didn't test. Restore the old behaviour by choosing for GPR3 r4 which results in two reloads in each alternative. * gcc.target/s390/asm-hard-reg-1.c: Similarly here we also compute a more precise conflicting register set which leads to choosing a different insn alternative for test_out_2. Diff: --- gcc/ira-lives.cc | 95 +++++++++++++++----------- gcc/testsuite/gcc.dg/asm-hard-reg-6.c | 4 +- gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c | 4 +- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/gcc/ira-lives.cc b/gcc/ira-lives.cc index 9103b3e4ff29..7b9c03e91ad6 100644 --- a/gcc/ira-lives.cc +++ b/gcc/ira-lives.cc @@ -846,16 +846,16 @@ mark_hard_reg_early_clobbers (rtx_insn *insn, bool live_p) } /* Checks that CONSTRAINTS permits to use only one hard register. If - it is so, the function returns the class of the hard register. - Otherwise it returns NO_REGS. */ -static enum reg_class -single_reg_class (const char *constraints, rtx op, rtx equiv_const) + it is so, the function returns the register. Otherwise it returns -1. */ +static int +single_reg_class_regno (const char *constraints, rtx op, rtx equiv_const) { int c; - enum reg_class cl, next_cl; + int regno, next_regno; + enum reg_class next_cl; enum constraint_num cn; - cl = NO_REGS; + regno = -1; alternative_mask preferred = preferred_alternatives; while ((c = *constraints)) { @@ -867,7 +867,14 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const) switch (c) { case 'g': - return NO_REGS; + return -1; + + case '{': + next_regno = decode_hard_reg_constraint (constraints); + if (regno >= 0 && regno != next_regno) + return -1; + regno = next_regno; + break; default: /* ??? Is this the best way to handle memory constraints? */ @@ -876,21 +883,21 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const) || insn_extra_special_memory_constraint (cn) || insn_extra_relaxed_memory_constraint (cn) || insn_extra_address_constraint (cn)) - return NO_REGS; + return -1; if (constraint_satisfied_p (op, cn) || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const) && constraint_satisfied_p (equiv_const, cn))) - return NO_REGS; + return -1; next_cl = reg_class_for_constraint (cn); if (next_cl == NO_REGS) break; - if (cl == NO_REGS - ? ira_class_singleton[next_cl][GET_MODE (op)] < 0 - : (ira_class_singleton[cl][GET_MODE (op)] - != ira_class_singleton[next_cl][GET_MODE (op)])) - return NO_REGS; - cl = next_cl; + next_regno = ira_class_singleton[next_cl][GET_MODE (op)]; + if (regno < 0 + ? next_regno < 0 + : regno != next_regno) + return -1; + regno = next_regno; break; case '0': case '1': case '2': case '3': case '4': @@ -899,33 +906,32 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const) char *end; unsigned long dup = strtoul (constraints, &end, 10); constraints = end; - next_cl - = single_reg_class (recog_data.constraints[dup], - recog_data.operand[dup], NULL_RTX); - if (cl == NO_REGS - ? ira_class_singleton[next_cl][GET_MODE (op)] < 0 - : (ira_class_singleton[cl][GET_MODE (op)] - != ira_class_singleton[next_cl][GET_MODE (op)])) - return NO_REGS; - cl = next_cl; + next_regno + = single_reg_class_regno (recog_data.constraints[dup], + recog_data.operand[dup], NULL_RTX); + if (regno < 0 + ? next_regno < 0 + : regno != next_regno) + return -1; + regno = next_regno; continue; } } constraints += CONSTRAINT_LEN (c, constraints); } - return cl; + return regno; } /* The function checks that operand OP_NUM of the current insn can use only one hard register. If it is so, the function returns the - class of the hard register. Otherwise it returns NO_REGS. */ -static enum reg_class -single_reg_operand_class (int op_num) + hard register. Otherwise it returns -1. */ +static int +single_reg_operand_class_regno (int op_num) { if (op_num < 0 || recog_data.n_alternatives == 0) - return NO_REGS; - return single_reg_class (recog_data.constraints[op_num], - recog_data.operand[op_num], NULL_RTX); + return -1; + return single_reg_class_regno (recog_data.constraints[op_num], + recog_data.operand[op_num], NULL_RTX); } /* The function sets up hard register set *SET to hard registers which @@ -989,9 +995,9 @@ ira_implicitly_set_insn_hard_regs (HARD_REG_SET *set, hard register and makes other currently living allocnos conflicting with the hard register. */ static void -process_single_reg_class_operands (bool in_p, int freq) +process_single_reg_constrained_operands (bool in_p, int freq) { - int i, regno; + int i, regno, hard_regno; unsigned int px; enum reg_class cl; rtx operand; @@ -1006,8 +1012,8 @@ process_single_reg_class_operands (bool in_p, int freq) if (! in_p && recog_data.operand_type[i] != OP_OUT && recog_data.operand_type[i] != OP_INOUT) continue; - cl = single_reg_operand_class (i); - if (cl == NO_REGS) + hard_regno = single_reg_operand_class_regno (i); + if (hard_regno < 0) continue; operand_a = NULL; @@ -1020,6 +1026,11 @@ process_single_reg_class_operands (bool in_p, int freq) { enum reg_class aclass; + cl = NO_REGS; + int nregs = hard_regno_nregs (hard_regno, recog_data.operand_mode[i]); + for (int j = 0; j < nregs; ++j) + cl = reg_class_superunion[cl][REGNO_REG_CLASS (hard_regno + j)]; + operand_a = ira_curr_regno_allocno_map[regno]; aclass = ALLOCNO_CLASS (operand_a); if (ira_class_subset_p[cl][aclass]) @@ -1036,7 +1047,7 @@ process_single_reg_class_operands (bool in_p, int freq) poly_int64 offset; xmode = recog_data.operand_mode[i]; - xregno = ira_class_singleton[cl][xmode]; + xregno = hard_regno; gcc_assert (xregno >= 0); ymode = ALLOCNO_MODE (operand_a); offset = subreg_lowpart_offset (ymode, xmode); @@ -1059,6 +1070,10 @@ process_single_reg_class_operands (bool in_p, int freq) } } + HARD_REG_SET hard_regs; + CLEAR_HARD_REG_SET (hard_regs); + add_to_hard_reg_set (&hard_regs, recog_data.operand_mode[i], hard_regno); + EXECUTE_IF_SET_IN_SPARSESET (objects_live, px) { ira_object_t obj = ira_object_id_map[px]; @@ -1068,8 +1083,8 @@ process_single_reg_class_operands (bool in_p, int freq) /* We could increase costs of A instead of making it conflicting with the hard register. But it works worse because it will be spilled in reload in anyway. */ - OBJECT_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl]; - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl]; + OBJECT_CONFLICT_HARD_REGS (obj) |= hard_regs; + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= hard_regs; } } } @@ -1540,7 +1555,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) preferred_alternatives = ira_setup_alts (insn); process_register_constraint_filters (); process_dependent_filters (); - process_single_reg_class_operands (false, freq); + process_single_reg_constrained_operands (false, freq); if (call_p) { @@ -1618,7 +1633,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) FOR_EACH_INSN_USE (use, insn) mark_ref_live (use); - process_single_reg_class_operands (true, freq); + process_single_reg_constrained_operands (true, freq); set_p = mark_hard_reg_early_clobbers (insn, true); diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-6.c b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c index c87a8116a869..b42b4d2c198a 100644 --- a/gcc/testsuite/gcc.dg/asm-hard-reg-6.c +++ b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c @@ -36,8 +36,8 @@ #elif defined (__s390__) # define GPR1 "{r0}" # define GPR2 "{r1}" -# define GPR3 "{r2}" -/* { dg-final { scan-assembler-times "foo\t%r0,%r2" 1 { target { s390*-*-* } } } } */ +# define GPR3 "{r4}" +/* { dg-final { scan-assembler-times "foo\t%r0,%r4" 1 { target { s390*-*-* } } } } */ /* { dg-final { scan-assembler-times "bar\t%r1,0\\(%r3\\)" 1 { target { s390*-*-* } } } } */ #elif defined (__x86_64__) # define GPR1 "{eax}" diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c index 671c0ede6efa..53ac46eb40c8 100644 --- a/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c +++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c @@ -75,8 +75,8 @@ test_out_1 (void) ** test_out_2: ** lgr (%r[0-9]+),%r2 ** foo %r2 -** ark (%r[0-9]+),\1,%r2 -** lgfr %r2,\2 +** ar %r2,\1 +** lgfr %r2,%r2 ** br %r14 */
