Hi Ulrich and group.

The i370 port of GCC 3.4.6 is now complete and the result can be
downloaded from http://gccmvs.sourceforge.net

It can be built using configure/make, and there weren't that many
changes that needed to be made to the code to get it to work.

However, I have encountered a bug.

I get bad code generated for this, because a non-s_operand is
getting through:

; Move a block that is less than 256 bytes in length.

(define_insn ""
 [(set (match_operand:BLK 0 "s_operand" "=m")
       (match_operand:BLK 1 "s_operand" "m"))
  (use (match_operand 2 "immediate_operand" "I"))]
 "((unsigned) INTVAL (operands[2]) < 256)"
 "*
{
 check_label_emit ();
 mvs_check_page (0, 6, 0);
 return \"MVC  %O0(%c2,%R0),%1\";
}"
  [(set_attr "length" "6")]
)

Here is the bad code:

L     9,=F'32880'
MVC   9(10,13),0(2)

That "9" in the MVC is supposed to be a constant from 0-4095. It
can't fit the large value in so has used a register, but then tried
to use that register in the instruction. It should have added R13
to R9 and used that as the base register (instead of the 13
you see)

I was surprised that an instruction that is marked as s_operand
was getting a seemingly non-s_operand given to it, so I added an
"S" constraint:

; Move a block that is less than 256 bytes in length.

(define_insn ""
 [(set (match_operand:BLK 0 "s_operand" "=S")
       (match_operand:BLK 1 "s_operand" "m"))

That then gave an actual compiler error instead of generating bad
code, which is a step forward:

pdos.c: In function `pdosLoadExe':
pdos.c:2703: error: unable to generate reloads for:
(insn 38 37 41 0 (parallel [
           (set (mem/s:BLK (plus:SI (reg/f:SI 13 13)
                       (const_int 32880 [0x8070])) [27 srchprog+0 S10 A64])
               (mem:BLK (reg/v/f:SI 2 2 [orig:27 prog ] [27]) [0 S10 A8]))
           (use (const_int 10 [0xa]))
       ]) 25 {*i370.md:1623} (insn_list 37 (nil))
   (expr_list:REG_DEAD (reg/v/f:SI 2 2 [orig:27 prog ] [27])
       (nil)))
pdos.c:2703: internal compiler error: in find_reloads, at reload.c:3690
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gccmvs.sourceforge.net> for instructions.


But I am surprised that s_operand and "S" are producing different
results.

Regardless, I sort of tracked the problem down to this bit of the
machine definition:

;
; movstrsi instruction pattern(s).
; block must be less than 16M (24 bits) in length

(define_expand "movstrsi"
 [(set (match_operand:BLK 0 "general_operand" "")
       (match_operand:BLK 1 "general_operand" ""))
  (use (match_operand:SI  2 "general_operand" ""))
  (match_operand 3 "" "")]
  ""
  "
{
 rtx op0, op1;

 op0 = XEXP (operands[0], 0);
 if (GET_CODE (op0) == REG
     || (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == REG
         && GET_CODE (XEXP (op0, 1)) == CONST_INT
         && (unsigned) INTVAL (XEXP (op0, 1)) < 4096))
   op0 = operands[0];
 else
op0 = replace_equiv_address (operands[0], copy_to_mode_reg (SImode, op0));

 op1 = XEXP (operands[1], 0);
 if (GET_CODE (op1) == REG
     || (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1, 0)) == REG
         && GET_CODE (XEXP (op1, 1)) == CONST_INT
         && (unsigned) INTVAL (XEXP (op1, 1)) < 4096))
   op1 = operands[1];
 else
op1 = replace_equiv_address (operands[1], copy_to_mode_reg (SImode, op1));

 if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 256)
   emit_insn (gen_rtx_PARALLEL (VOIDmode,
                       gen_rtvec (2,
                                  gen_rtx_SET (VOIDmode, op0, op1),
                                  gen_rtx_USE (VOIDmode, operands[2]))));


So now I am basically wanting to stop this code from doing that emit_insn.
I tested putting in a kludge to see if operands[2] was equal to 10 (the
length in my test case), and bypassing the emit_insn. That forced it to
use a more inefficient move instruction, but that's fine.

So I need some way of getting op0 detected as "unsuitable for use in
an MVC". I have put in debug and found that GET_CODE(op0) is equal
to MEM. I have also found that GET_CODE(XEXP(op0, 0)) is a REG_P,
whatever that means (I was just copying things I saw in the
s_operand test). Here is the s_operand test for reference:

/* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
  OP is the current operation.
  MODE is the current operation mode.  */

int
s_operand (register rtx op, enum machine_mode mode)
{
 extern int volatile_ok;
 register enum rtx_code code = GET_CODE (op);

 if (CONSTANT_ADDRESS_P (op))
   return 1;
 if (mode == VOIDmode || GET_MODE (op) != mode)
   return 0;
 if (code == MEM)
   {
     register rtx x = XEXP (op, 0);

     if (!volatile_ok && op->volatil)
       return 0;
     if (REG_P (x) && REG_OK_FOR_BASE_P (x))
       return 1;
     if (GET_CODE (x) == PLUS
         && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
         && GET_CODE (XEXP (x, 1)) == CONST_INT
         && (unsigned) INTVAL (XEXP (x, 1)) < 4096)
       return 1;
   }
 return 0;
}

Now because I know that it is MEM and REG_P, I can actually
put in a check to detect that and abort it.

But that then causes more inefficient code to be generated
in other circumstances:

<          L     2,12(4)
<          MVC   104(24,13),0(2)
---
         LA    4,104(,13)
         LA    5,24(0,0)
         L     2,12(6)
         LR    3,5
         MVCL  4,2

Any idea what can be done?

Thanks.  Paul.

Reply via email to