Thanks for reaching out, Julian, I greatly appreciate your help. Please
forgive and over- or under-sharing. If I've left something out, please let
me know.
>From my pdp10.md:
;; JIRA sw_gcc-68. gcc recognizes the "movmemhi" 'instruction' for
;; doing block moves, as in struct assignment. This pattern wasn't
;; present, however. I've added it, and it's companion function
;; pdp10_expand_movmemhi().
(define_expand "movmemhi"
[(match_operand:BLK 0 "general_operand" "=r")
(match_operand:BLK 1 "general_operand" "=r")
(match_operand:SI 2 "general_operand" "=r")
(match_operand:SI 3 "const_int_operand" "")
]
""
{
if (pdp10_expand_movmemhi(operands)) {
DONE;
}
FAIL;
/*
* if (!pdp10_expand_movmemhi(operands)) {
* FAIL;
* }
*/
}
)
And the definition for pdp10_expand_movmemhi:
// JIRA sw_gcc-68: Emit instructions to copy a memory block. Return
// nonzero on success. This is really a duplicate of the following
// function, but used specifically for the movmemhi operation.
// Duplicated to allow for any custimization.
int pdp10_expand_movmemhi(rtx *operands) {
// operands[0] is the block destination address
// operands[1] is the block source address
// operands[2] is the block length
// operands[3] is the known alignment.
if (flag_enable_fix_sw_gcc_0068) {
operands[0] = XEXP(operands[0], 0);
operands[1] = XEXP(operands[1], 0);
if (GET_CODE(operands[3]) != CONST_INT) {
return 0;
}
if (INTVAL(operands[3]) != UNITS_PER_WORD) {
return 0;
}
if (GET_CODE(operands[1]) == CONST &&
GET_CODE(XEXP(operands[1], 0)) == PLUS &&
GET_CODE(XEXP(XEXP(operands[1], 0), 1)) == CONST_INT
)
{
rtx x = XEXP(operands[1], 0);
HOST_WIDE_INT offset = INTVAL(XEXP(x, 1));
operands[1] = plus_constant(XEXP(x, 0), offset & ADDRESS_MASK);
}
if (use_xblt(operands[0], operands[1], operands[2])) {
return expand_xblt(operands[0], operands[1], operands[2]);
}
return expand_blt(operands[0], operands[1], operands[2]);
}
return 0;
}
Here are use_xblt() and expand_xblt():
// Return nonzero if XBLT should be used instead of BLT.
static int use_xblt(rtx destination, rtx source, rtx length) {
if (!HAVE_XBLT || !TARGET_EXTENDED) {
return 0;
}
if (GET_CODE(destination) != CONST_INT) {
return 1;
}
if (source && GET_CODE(source) != CONST_INT) {
return 1;
}
if (GET_CODE(length) != CONST_INT) {
return 1;
}
if (INTVAL(length) >> 32 > 0) {
return 1;
}
if (source) {
HOST_WIDE_INT destination_section = INTVAL(destination) >> 32;
HOST_WIDE_INT source_section = INTVAL(source) >> 32;
if (destination_section != source_section) {
return 1;
}
}
return 0;
}
// Try to emit instructions to XBLT a memory block of LENGTH storage
// units from SOURCE to DESTINATION. Return nonzero on success.
static int expand_xblt(rtx destination, rtx source, rtx length) {
rtx temp, mem, acs;
int i, n;
if (GET_CODE(length) != CONST_INT) {
return 0;
}
n = INTVAL(length);
switch (n / UNITS_PER_WORD) {
case 0:
break;
case 2:
case 3:
temp = gen_reg_rtx(DImode);
for (i = 0; i < n / 8; i++) {
emit_move_insn(temp, gen_rtx_MEM(DImode, plus_constant(source, i)));
emit_move_insn(gen_rtx_MEM(DImode, plus_constant(destination, i)),
temp);
}
// Fall through.
case 1:
if (n % 8 >= 4) {
int m = 2 * (n / 8);
temp = gen_reg_rtx(SImode);
emit_move_insn(temp, gen_rtx_MEM(SImode, plus_constant(source, m)));
emit_move_insn(gen_rtx_MEM(SImode, plus_constant(destination, m)),
temp);
}
break;
default:
acs = gen_reg_rtx(TImode);
emit_move_insn(gen_rtx_SUBREG(SImode, acs, 0), GEN_INT(INTVAL(length)
/ UNITS_PER_WORD));
emit_move_insn(gen_rtx_SUBREG(Pmode, acs, 4), source);
emit_move_insn(gen_rtx_SUBREG(Pmode, acs, 8), destination);
emit_insn(gen_XBLT(acs));
break;
}
switch (n % UNITS_PER_WORD) {
case 0:
break;
case 1:
temp = gen_reg_rtx(QImode);
mem = gen_rtx_MEM(QImode, plus_constant(source, n / 4));
set_mem_align(mem, BITS_PER_WORD);
emit_move_insn(temp, mem);
mem = gen_rtx_MEM(QImode, plus_constant(destination, n / 4));
set_mem_align(mem, BITS_PER_WORD);
emit_move_insn(mem, temp);
break;
case 2:
temp = gen_reg_rtx(HImode);
mem = gen_rtx_MEM(HImode, plus_constant(source, n / 4));
set_mem_align(mem, BITS_PER_WORD);
emit_move_insn(temp, mem);
mem = gen_rtx_MEM(HImode, plus_constant(destination, n / 4));
set_mem_align(mem, BITS_PER_WORD);
emit_move_insn(mem, temp);
break;
case 3:
temp = gen_reg_rtx(SImode);
emit_insn(gen_extzv(temp, gen_rtx_MEM(SImode, plus_constant(source, n
/ 4)), GEN_INT(27), GEN_INT(0)));