mmix: fix gcc.dg/loop-9.c by more accurate move insns
authorHans-Peter Nilsson <hp@bitrange.com>
Thu, 6 Aug 2020 23:57:15 +0000 (01:57 +0200)
committerHans-Peter Nilsson <hp@bitrange.com>
Thu, 6 Aug 2020 23:57:15 +0000 (01:57 +0200)
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<mode>"): New expander to expand for all MM-modes.
("*movqi_expanded", "*movhi_expanded", "*movsi_expanded")
("*movsf_expanded", "*movdf_expanded"): Rename from the
corresponding mov<M> 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

index d49297af083bac4ff37a141e49c92f3e49f3d441..f41a5b260ddadc698e6e5e70e1480e6b074a16d1 100644 (file)
@@ -38,6 +38,8 @@
    (MMIX_rR_REGNUM 260)
    (MMIX_fp_rO_OFFSET -24)]
 )
+
+(define_mode_iterator MM [QI HI SI DI SF DF])
 \f
 ;; Operand and operator predicates.
 
 \f
 ;; FIXME: Can we remove the reg-to-reg for smaller modes?  Shouldn't they
 ;; be synthesized ok?
-(define_insn "movqi"
+(define_expand "mov<mode>"
+  [(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>mode != DImode
+         || !memory_operand (operands[0], DImode)
+         || !satisfies_constraint_I (operands[1])))
+    operands[1] = force_reg (<MODE>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
    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
    %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
    %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
 
 ;; 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
    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