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.