From 11b8ffa493039e8da3a7bc7d3c14354735d41e46 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Fri, 7 Aug 2020 01:57:15 +0200 Subject: [PATCH] mmix: fix gcc.dg/loop-9.c by more accurate move insns It looks like gcc.dg/loop-9.c kind-of works as sentinel for sane move-instruction generation for a port. Looking at the FAIL: gcc.dg/loop-9.c scan-rtl-dump loop2_invariant "Decided" FAIL: gcc.dg/loop-9.c scan-rtl-dump loop2_invariant "without introducing a new temporary register" it seems the problem is that in the loop: for (i = 0; i < 100; i++) a[i] = 18.4242; the move insn corresponding to "a[i] = 18.4242" happens to be generated as a move of a constant to a memory address, using no registers except for the address (edited): (insn 9 8 10 3 (set (mem:DF (reg:DI 269 [ ivtmp::9 ])) (const_double:DF 1.84241999e+1)) "x/loop-9.c":9:10 6 {movdf}) To wit, at the loop2 pass there's no register-initialization to move out of the loop! The insn above isn't accurate and has to be fixed up at register allocation time to make constraints match. While there are insns to set memory to constant in MMIX, that's limited to 64-bit moves corresponding to the integer bit-patterns for 0..255, and 18.4242 isn't one of them. (Only 0.0 matches; the bit-patterns for 0..255 would IIUC be interpreted as denormal floating-point numbers a.k.a. subnormal numbers and don't seem worthwhile to handle.) The fault is with the port, for not requiring a register for an operand that actually requires an intermediate register, in order to enable pre-register-allocation passes to do their job. The movdf pattern (actually, all MMIX movM), only required the destination to be a non-immediate operand and the source to be a general_operand, i.e. anything-to-anything. Better force the source to be a register, when asked to generate such a move insn. Also, make operands stay sane by using the matching insn condition to require one of the operands to be a register pre-register-allocation (for sake of combine-like passes that cook up "simplified" insns, possibly losing the use of a register). Looking no deeper than at the results of test-runs with different variants, I see that the latter "safety latch" has no effect on the test-results (at 919c9d4bd3db7da0), but it just feels like the right thing to do. Similarly, there's no effect on test-suite results, to do the same not just for movdf but for all moves. gcc: * config/mmix/mmix.md (MM): New mode_iterator. ("mov"): New expander to expand for all MM-modes. ("*movqi_expanded", "*movhi_expanded", "*movsi_expanded") ("*movsf_expanded", "*movdf_expanded"): Rename from the corresponding mov named pattern. Add to the condition that either operand must be a register_operand. ("*movdi_expanded"): Similar, but also allow STCO in the condition. --- gcc/config/mmix/mmix.md | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/gcc/config/mmix/mmix.md b/gcc/config/mmix/mmix.md index d49297af083..f41a5b260dd 100644 --- a/gcc/config/mmix/mmix.md +++ b/gcc/config/mmix/mmix.md @@ -38,6 +38,8 @@ (MMIX_rR_REGNUM 260) (MMIX_fp_rO_OFFSET -24)] ) + +(define_mode_iterator MM [QI HI SI DI SF DF]) ;; Operand and operator predicates. @@ -46,10 +48,25 @@ ;; FIXME: Can we remove the reg-to-reg for smaller modes? Shouldn't they ;; be synthesized ok? -(define_insn "movqi" +(define_expand "mov" + [(set (match_operand:MM 0 "nonimmediate_operand") + (match_operand:MM 1 "general_operand"))] + "" +{ + /* Help pre-register-allocation to use at least one register in a move. + FIXME: support STCO also for DFmode (storing 0.0). */ + if (!REG_P (operands[0]) && !REG_P (operands[1]) + && (mode != DImode + || !memory_operand (operands[0], DImode) + || !satisfies_constraint_I (operands[1]))) + operands[1] = force_reg (mode, operands[1]); +}) + +(define_insn "*movqi_expanded" [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r ,r,x ,r,r,m,??r") (match_operand:QI 1 "general_operand" "r,LS,K,rI,x,m,r,n"))] - "" + "register_operand (operands[0], QImode) + || register_operand (operands[1], QImode)" "@ SET %0,%1 %s1 %0,%v1 @@ -60,10 +77,11 @@ STBU %1,%0 %r0%I1") -(define_insn "movhi" +(define_insn "*movhi_expanded" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r ,r ,x,r,r,m,??r") (match_operand:HI 1 "general_operand" "r,LS,K,r,x,m,r,n"))] - "" + "register_operand (operands[0], HImode) + || register_operand (operands[1], HImode)" "@ SET %0,%1 %s1 %0,%v1 @@ -75,10 +93,11 @@ %r0%I1") ;; gcc.c-torture/compile/920428-2.c fails if there's no "n". -(define_insn "movsi" +(define_insn "*movsi_expanded" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r ,r,x,r,r,m,??r") (match_operand:SI 1 "general_operand" "r,LS,K,r,x,m,r,n"))] - "" + "register_operand (operands[0], SImode) + || register_operand (operands[1], SImode)" "@ SET %0,%1 %s1 %0,%v1 @@ -90,10 +109,13 @@ %r0%I1") ;; We assume all "s" are addresses. Does that hold? -(define_insn "movdi" +(define_insn "*movdi_expanded" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,r,??r") (match_operand:DI 1 "general_operand" "r,LS,K,r,x,I,m,r,R,s,n"))] - "" + "register_operand (operands[0], DImode) + || register_operand (operands[1], DImode) + || (memory_operand (operands[0], DImode) + && satisfies_constraint_I (operands[1]))" "@ SET %0,%1 %s1 %0,%v1 @@ -109,10 +131,11 @@ ;; Note that we move around the float as a collection of bits; no ;; conversion to double. -(define_insn "movsf" +(define_insn "*movsf_expanded" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r") (match_operand:SF 1 "general_operand" "r,G,r,x,m,r,F"))] - "" + "register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode)" "@ SET %0,%1 SETL %0,0 @@ -122,10 +145,11 @@ STTU %1,%0 %r0%I1") -(define_insn "movdf" +(define_insn "*movdf_expanded" [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r") (match_operand:DF 1 "general_operand" "r,G,r,x,m,r,F"))] - "" + "register_operand (operands[0], DFmode) + || register_operand (operands[1], DFmode)" "@ SET %0,%1 SETL %0,0 -- 2.30.2