From: Stefan Schulze Frielinghaus <[email protected]>
This fixes
t.c:6:1: error: unable to find a register to spill
6 | }
| ^
for target avr. In the PR we are given a patch which makes use of hard
register constraints in the machine description for divmodhi4. Prior
combine we have for the test from the PR
(insn 7 6 8 2 (parallel [
(set (reg:HI 46 [ _1 ])
(div:HI (reg/v:HI 44 [ k ])
(reg:HI 48)))
(set (reg:HI 47)
(mod:HI (reg/v:HI 44 [ k ])
(reg:HI 48)))
(clobber (scratch:HI))
(clobber (scratch:QI))
]) "t.c":5:5 602 {divmodhi4}
(expr_list:REG_DEAD (reg:HI 48)
(expr_list:REG_DEAD (reg/v:HI 44 [ k ])
(expr_list:REG_UNUSED (reg:HI 47)
(nil)))))
(insn 8 7 9 2 (set (reg:HI 22 r22)
(symbol_ref/f:HI ("*.LC0") [flags 0x2] <var_decl 0x3fff7950d10
*.LC0>)) "t.c":5:5 128 {*movhi_split}
(nil))
(insn 9 8 10 2 (set (reg:HI 24 r24)
(reg:HI 46 [ _1 ])) "t.c":5:5 128 {*movhi_split}
(expr_list:REG_DEAD (reg:HI 46 [ _1 ])
(nil)))
The patched instruction divmodhi4 constraints operand 2 (here pseudo
48) to hard register 22. Combine merges insn 7 into 9 by crossing a
hard register assignment of register 22.
(note 7 6 8 2 NOTE_INSN_DELETED)
(insn 8 7 9 2 (set (reg:HI 22 r22)
(symbol_ref/f:HI ("*.LC0") [flags 0x2] <var_decl 0x3fff7950d10
*.LC0>)) "t.c":5:5 128 {*movhi_split}
(nil))
(insn 9 8 10 2 (parallel [
(set (reg:HI 24 r24)
(div:HI (reg:HI 49 [ k ])
(reg:HI 48)))
(set (reg:HI 47)
(mod:HI (reg:HI 49 [ k ])
(reg:HI 48)))
(clobber (scratch:HI))
(clobber (scratch:QI))
]) "t.c":5:5 602 {divmodhi4}
(expr_list:REG_DEAD (reg:HI 48)
(expr_list:REG_DEAD (reg:HI 49 [ k ])
(nil))))
This leaves us with a conflict for pseudo 48 in the updated insn 9 since
register 22 is live here.
Fixed by pulling the sledge hammer and skipping any logical link if a
single register constraint is possibly involved. Ideally we would skip
based on the fact whether there is any usage of a hard register referred
by any single register constraint between INSN and USE_INSN during
combine.
gcc/ChangeLog:
* combine.cc (has_single_register_constraint_p): New function.
(create_log_links): Do not build LOG_LINKs between insns
containing single register constraints.
---
gcc/combine.cc | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/gcc/combine.cc b/gcc/combine.cc
index 816324f4735..1ea99d1697c 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3. If not see
#include "regs.h"
#include "emit-rtl.h"
#include "recog.h"
+#include "ira.h"
#include "cgraph.h"
#include "stor-layout.h"
#include "cfgrtl.h"
@@ -1020,6 +1021,60 @@ can_combine_use_p (df_ref use)
return true;
}
+/* Return true if INSN has a single register constraint like a constraint
+ associated with a single register class or a hard register constraint.
+ Otherwise return false. */
+static bool
+has_single_register_constraint_p (rtx_insn *insn)
+{
+ extract_insn (insn);
+ for (int nop = recog_data.n_operands - 1; nop >= 0; --nop)
+ {
+ int c;
+ const char *p = recog_data.constraints[nop];
+ for (; (c = *p); p += CONSTRAINT_LEN (c, p))
+ if (c == ',')
+ ;
+ else if (c == '{')
+ return true;
+ /* For the moment ignore constraints with single register classes since
+ this would introduce missed optimizations. Although, this literally
+ means we ICE in certain cases. For example, on powerpc64le tests
+
+ FAIL: gcc.dg/cpp/_Pragma3.c (test for excess errors)
+ FAIL: gcc.target/powerpc/fold-vec-extract-char.p7.c
scan-assembler-times \\mrldicl\\M|\\mrlwinm\\M 3
+ FAIL: gcc.target/powerpc/fold-vec-extract-short.p7.c
scan-assembler-times \\mrldic\\M|\\mrlwinm\\M 3
+ FAIL: gcc.target/powerpc/fusion-p10-ldcmpi.c scan-assembler-times
lbz_cmpldi_cr0_QI_clobber_CCUNS_zero 4
+ FAIL: gcc.target/powerpc/fusion-p10-ldcmpi.c scan-assembler-times
lha_cmpdi_cr0_HI_clobber_CC_sign 16
+ FAIL: gcc.target/powerpc/fusion-p10-ldcmpi.c scan-assembler-times
lhz_cmpldi_cr0_HI_clobber_CCUNS_zero 4
+ FAIL: gcc.target/powerpc/p9-splat-2.c scan-assembler-times lxvwsx 1
+ FAIL: gcc.target/powerpc/p9-splat-2.c scan-assembler-times xscvdpspn 2
+ FAIL: gcc.target/powerpc/p9-splat-2.c scan-assembler-times xxspltw 2
+ FAIL: gcc.target/powerpc/prefix-ds-dq.c scan-assembler-times \\mlha\\M
1
+ FAIL: gcc.target/powerpc/prefix-ds-dq.c scan-assembler-times \\mlhz\\M
1
+ FAIL: gcc.target/powerpc/vector_float.c scan-assembler-times
\\mrldimi\\M 2
+ FAIL: gcc.target/powerpc/vsx-builtin-7.c scan-assembler-times xxpermdi
35
+
+ would fail because constraint c is referring to the single count
+ register. This should be fixed by not using a sledge hammer as
+ described below. */
+#if 0
+ else
+ {
+ enum reg_class cl
+ = reg_class_for_constraint (lookup_constraint (p));
+ if (cl == NO_REGS)
+ continue;
+ machine_mode mode = recog_data.operand_mode[nop];
+ int regno = ira_class_singleton[cl][mode];
+ if (regno >= 0)
+ return true;
+ }
+#endif
+ }
+ return false;
+}
+
/* Fill in log links field for all insns. */
static void
@@ -1051,6 +1106,9 @@ create_log_links (void)
/* Log links are created only once. */
gcc_assert (!LOG_LINKS (insn));
+ bool has_single_reg_cstr
+ = has_single_register_constraint_p (insn);
+
FOR_EACH_INSN_DEF (def, insn)
{
unsigned int regno = DF_REF_REGNO (def);
@@ -1079,6 +1137,23 @@ create_log_links (void)
&& asm_noperands (PATTERN (use_insn)) >= 0)
continue;
+ /* Do not build LOG_LINKs between insns containing single
+ register constraints. For example, assume that in the first
+ insn operand r100 of exp_a is constrained to hard register %5.
+
+ r101=exp_a(r100)
+ %5=...
+ r102=exp_b(r101)
+
+ Then combining the first insn into the last one creates a
+ conflict for pseudo r100 since hard register %5 is live.
+ Therefore, skip for now. This is a sledge hammer approach.
+ Ideally we would skip based on the fact whether there is any
+ definition of a hard register used in a single register
+ constraint between INSN and USE_INSN. */
+ if (has_single_reg_cstr)
+ continue;
+
/* Don't add duplicate links between instructions. */
struct insn_link *links;
FOR_EACH_LOG_LINK (links, use_insn)
--
2.52.0