OK, let's start again from scratch. This patch fixes PR61098, a problem caused by trying to do arithmetic on the count register. The fix is to provide a new pseudo in rs6000_emit_set_long_const so arithmetic will be done in a gpr.
Additionally, the patch fixes a number of other bugs and cleanup issues with rs6000_emit_set_{,long_}const. - rs6000_emit_set_long_const took two HWI constant parameters, a relic from the days when HWI might be 32 bits on powerpc. We're only setting a 64-bit value, so remove the unnecessary parameter. - The !TARGET_POWERPC64 handling of DImode assumed a 32 bit HWI, and the insn setting the low 32-bit reg was wrongly marked with a reg_equiv note saying the reg contained the entire 64-bit constant. I hadn't spotted the bad reg_equiv when writing the previous patch. - The comments describing the functions are inaccurate and misleading. - rs6000_emit_set_long_const always returns DEST, so it's caller can assume this and rs6000_emit_set_long_const return void. - The code testing for a NULL DEST in rs6000_emit_set_const is dead. DEST cannot be NULL, since the three uses of the function are in rs6000.md splitters where DEST (operand[0]) satisfies gpc_reg_operand. - The above two points mean that rs6000_emit_set_const always returns DEST, which in turn would allow rs6000_emit_set_const to return void. However, in view of a possible future change that might need to return status on whether rs6000_emit_set_const emitted anything, return a bool. - rs6000_emit_set_const parameter N is currently unused, and MODE always matches GET_MODE (DEST), so N and MODE can be removed. - The code is liberally sprinkled with copy_rtx. DEST/TEMP is always used once without copy_rtx, but which insn uses copy_rtx varies. I changed the code to always use a bare DEST as the last insn for consistency. (Writing the code this way might allow us to omit the copy_rtx on DEST/TEMP entirely. Before reload TEMP will be a new pseudo reg, thus doesn't need copy_rtx, and after reload we shouldn't have a SUBREG DEST. I wasn't sure of exactly what might happen during reload, so left well enough alone.) Bootstrapped and regression tested powerpc64-linux. OK to apply mainline? PR target/61098 * config/rs6000/rs6000.c (rs6000_emit_set_const): Remove unneeded params and return a bool. Remove dead code. Update comment. Assert we have a const_int source. Remove bogus code from 32-bit HWI days. Move !TARGET_POWERPC64 handling, and correct handling of constants > 2G and reg_equal note, from.. (rs6000_emit_set_long_const): ..here. Remove unneeded param and return value. Update comment. If we can, use a new pseudo for intermediate calculations. * config/rs6000/rs6000-protos.h (rs6000_emit_set_const): Update prototype. * config/rs6000/rs6000.md (movsi_internal1_single+1): Update call to rs6000_emit_set_const in splitter. (movdi_internal64+2, +3): Likewise. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 210835) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -1068,7 +1068,7 @@ static tree rs6000_handle_longcall_attribute (tree static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *); static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *); static tree rs6000_builtin_vectorized_libmass (tree, tree, tree); -static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT); +static void rs6000_emit_set_long_const (rtx, HOST_WIDE_INT); static int rs6000_memory_move_cost (enum machine_mode, reg_class_t, bool); static bool rs6000_debug_rtx_costs (rtx, int, int, int, int *, bool); static int rs6000_debug_address_cost (rtx, enum machine_mode, addr_space_t, @@ -7849,53 +7849,50 @@ rs6000_conditional_register_usage (void) } -/* Try to output insns to set TARGET equal to the constant C if it can - be done in less than N insns. Do all computations in MODE. - Returns the place where the output has been placed if it can be - done and the insns have been emitted. If it would take more than N - insns, zero is returned and no insns and emitted. */ +/* Output insns to set DEST equal to the constant SOURCE as a series of + lis, ori and shl instructions and return TRUE. */ -rtx -rs6000_emit_set_const (rtx dest, enum machine_mode mode, - rtx source, int n ATTRIBUTE_UNUSED) +bool +rs6000_emit_set_const (rtx dest, rtx source) { - rtx result, insn, set; - HOST_WIDE_INT c0, c1; + enum machine_mode mode = GET_MODE (dest); + rtx temp, insn, set; + HOST_WIDE_INT c; + gcc_checking_assert (CONST_INT_P (source)); + c = INTVAL (source); switch (mode) { - case QImode: + case QImode: case HImode: - if (dest == NULL) - dest = gen_reg_rtx (mode); emit_insn (gen_rtx_SET (VOIDmode, dest, source)); - return dest; + return true; case SImode: - result = !can_create_pseudo_p () ? dest : gen_reg_rtx (SImode); + temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (result), - GEN_INT (INTVAL (source) - & (~ (HOST_WIDE_INT) 0xffff)))); + emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (temp), + GEN_INT (c & ~(HOST_WIDE_INT) 0xffff))); emit_insn (gen_rtx_SET (VOIDmode, dest, - gen_rtx_IOR (SImode, copy_rtx (result), - GEN_INT (INTVAL (source) & 0xffff)))); - result = dest; + gen_rtx_IOR (SImode, copy_rtx (temp), + GEN_INT (c & 0xffff)))); break; case DImode: - switch (GET_CODE (source)) + if (!TARGET_POWERPC64) { - case CONST_INT: - c0 = INTVAL (source); - c1 = -(c0 < 0); - break; + rtx hi, lo; - default: - gcc_unreachable (); + hi = operand_subword_force (copy_rtx (dest), WORDS_BIG_ENDIAN == 0, + DImode); + lo = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0, + DImode); + emit_move_insn (hi, GEN_INT (c >> 32)); + c = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000; + emit_move_insn (lo, GEN_INT (c)); } - - result = rs6000_emit_set_long_const (dest, c0, c1); + else + rs6000_emit_set_long_const (dest, c); break; default: @@ -7905,107 +7902,103 @@ rs6000_conditional_register_usage (void) insn = get_last_insn (); set = single_set (insn); if (! CONSTANT_P (SET_SRC (set))) - set_unique_reg_note (insn, REG_EQUAL, source); + set_unique_reg_note (insn, REG_EQUAL, GEN_INT (c)); - return result; + return true; } -/* Having failed to find a 3 insn sequence in rs6000_emit_set_const, - fall back to a straight forward decomposition. We do this to avoid - exponential run times encountered when looking for longer sequences - with rs6000_emit_set_const. */ -static rtx -rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2) +/* Subroutine of rs6000_emit_set_const, handling PowerPC64 DImode. + Output insns to set DEST equal to the constant C as a series of + lis, ori and shl instructions. */ + +static void +rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c) { - if (!TARGET_POWERPC64) + rtx temp; + HOST_WIDE_INT ud1, ud2, ud3, ud4; + + ud1 = c & 0xffff; + c = c >> 16; + ud2 = c & 0xffff; + c = c >> 16; + ud3 = c & 0xffff; + c = c >> 16; + ud4 = c & 0xffff; + + if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000)) + || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000))) + emit_move_insn (dest, GEN_INT ((ud1 ^ 0x8000) - 0x8000)); + + else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000)) + || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000))) { - rtx operand1, operand2; + temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (DImode); - operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0, - DImode); - operand2 = operand_subword_force (copy_rtx (dest), WORDS_BIG_ENDIAN != 0, - DImode); - emit_move_insn (operand1, GEN_INT (c1)); - emit_move_insn (operand2, GEN_INT (c2)); + emit_move_insn (ud1 != 0 ? copy_rtx (temp) : dest, + GEN_INT (((ud2 << 16) ^ 0x80000000) - 0x80000000)); + if (ud1 != 0) + emit_move_insn (dest, + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud1))); } - else + else if (ud3 == 0 && ud4 == 0) { - HOST_WIDE_INT ud1, ud2, ud3, ud4; + temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (DImode); - ud1 = c1 & 0xffff; - ud2 = (c1 & 0xffff0000) >> 16; - c2 = c1 >> 32; - ud3 = c2 & 0xffff; - ud4 = (c2 & 0xffff0000) >> 16; + gcc_assert (ud2 & 0x8000); + emit_move_insn (copy_rtx (temp), + GEN_INT (((ud2 << 16) ^ 0x80000000) - 0x80000000)); + if (ud1 != 0) + emit_move_insn (copy_rtx (temp), + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud1))); + emit_move_insn (dest, + gen_rtx_ZERO_EXTEND (DImode, + gen_lowpart (SImode, + copy_rtx (temp)))); + } + else if ((ud4 == 0xffff && (ud3 & 0x8000)) + || (ud4 == 0 && ! (ud3 & 0x8000))) + { + temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (DImode); - if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000)) - || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000))) - emit_move_insn (dest, GEN_INT ((ud1 ^ 0x8000) - 0x8000)); + emit_move_insn (copy_rtx (temp), + GEN_INT (((ud3 << 16) ^ 0x80000000) - 0x80000000)); + if (ud2 != 0) + emit_move_insn (copy_rtx (temp), + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud2))); + emit_move_insn (ud1 != 0 ? copy_rtx (temp) : dest, + gen_rtx_ASHIFT (DImode, copy_rtx (temp), + GEN_INT (16))); + if (ud1 != 0) + emit_move_insn (dest, + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud1))); + } + else + { + temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (DImode); - else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000)) - || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000))) - { - emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000) - - 0x80000000)); - if (ud1 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud1))); - } - else if (ud3 == 0 && ud4 == 0) - { - gcc_assert (ud2 & 0x8000); - emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000) - - 0x80000000)); - if (ud1 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud1))); - emit_move_insn (copy_rtx (dest), - gen_rtx_ZERO_EXTEND (DImode, - gen_lowpart (SImode, - copy_rtx (dest)))); - } - else if ((ud4 == 0xffff && (ud3 & 0x8000)) - || (ud4 == 0 && ! (ud3 & 0x8000))) - { - emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000) - - 0x80000000)); - if (ud2 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud2))); - emit_move_insn (copy_rtx (dest), - gen_rtx_ASHIFT (DImode, copy_rtx (dest), - GEN_INT (16))); - if (ud1 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud1))); - } - else - { - emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000) - - 0x80000000)); - if (ud3 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud3))); + emit_move_insn (copy_rtx (temp), + GEN_INT (((ud4 << 16) ^ 0x80000000) - 0x80000000)); + if (ud3 != 0) + emit_move_insn (copy_rtx (temp), + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud3))); - emit_move_insn (copy_rtx (dest), - gen_rtx_ASHIFT (DImode, copy_rtx (dest), - GEN_INT (32))); - if (ud2 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud2 << 16))); - if (ud1 != 0) - emit_move_insn (copy_rtx (dest), - gen_rtx_IOR (DImode, copy_rtx (dest), - GEN_INT (ud1))); - } + emit_move_insn (ud2 != 0 || ud1 != 0 ? copy_rtx (temp) : dest, + gen_rtx_ASHIFT (DImode, copy_rtx (temp), + GEN_INT (32))); + if (ud2 != 0) + emit_move_insn (ud1 != 0 ? copy_rtx (temp) : dest, + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud2 << 16))); + if (ud1 != 0) + emit_move_insn (dest, + gen_rtx_IOR (DImode, copy_rtx (temp), + GEN_INT (ud1))); } - return dest; } /* Helper for the following. Get rid of [r+r] memory refs Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 210835) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -8850,9 +8850,8 @@ (ior:SI (match_dup 0) (match_dup 3)))] " -{ rtx tem = rs6000_emit_set_const (operands[0], SImode, operands[1], 2); - - if (tem == operands[0]) +{ + if (rs6000_emit_set_const (operands[0], operands[1])) DONE; else FAIL; @@ -9922,9 +9921,8 @@ [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] " -{ rtx tem = rs6000_emit_set_const (operands[0], DImode, operands[1], 5); - - if (tem == operands[0]) +{ + if (rs6000_emit_set_const (operands[0], operands[1])) DONE; else FAIL; @@ -9937,9 +9935,8 @@ [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] " -{ rtx tem = rs6000_emit_set_const (operands[0], DImode, operands[1], 5); - - if (tem == operands[0]) +{ + if (rs6000_emit_set_const (operands[0], operands[1])) DONE; else FAIL; Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 210834) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -114,7 +114,7 @@ extern void rs6000_emit_cbranch (enum machine_mode extern char * output_cbranch (rtx, const char *, int, rtx); extern char * output_e500_flip_gt_bit (rtx, rtx); extern const char * output_probe_stack_range (rtx, rtx); -extern rtx rs6000_emit_set_const (rtx, enum machine_mode, rtx, int); +extern bool rs6000_emit_set_const (rtx, rtx); extern int rs6000_emit_cmove (rtx, rtx, rtx, rtx); extern int rs6000_emit_vector_cond_expr (rtx, rtx, rtx, rtx, rtx, rtx); extern void rs6000_emit_minmax (rtx, enum rtx_code, rtx, rtx); -- Alan Modra Australia Development Lab, IBM