The attached change fixes an ICE caused by pa_output_move_double's failure to handle a DImode high const_int operand, (high:DI (const_int 86400000000 [0x141dd76000])). The need to handle this operand form in pa_output_move_double is quite infrequent, so the problem has gone unnoticed for many years.
This issue only affects 32-bit targets. DImode constants are split by pa_emit_move_sequence into high and lo_sum parts. These parts are handled by separate insn patterns in pa.md. There is a third pattern which handles all other DImode moves using pa_output_move_double for moves involving the integer registers. There is an 'i' immediate_operand constraint to handle immediate operands. The problem occurs when an equivalent reg value, REG_EQUIV (high:DI (const_int 86400000000 [0x141dd76000])), is substituted for a register operand and the instruction is NOT re-recognized. Splitting DImode constants was presumably done to improve optimization opportunities. However, this only works because the predicate does not allow immediate operands. This is not recommended since insn recognition may fail if an immediate operand is substituted (e.g., a const_int) as there is no predicate that accepts a const_int. However, if the predicate is changed to allow immediate operands, then the high/lo_sum splits are just put back together and the optimization benefit lost. There is no cost benefit in doing this, so I'm not sure why it happens. There is also an issue regarding the insn length when we have a high immediate operand. It should be 12 not 16 for that case. I intend to look at fixing this but it's not a major issue. Tested on hppa-unknown-linux-gnu and hppa2.0w-hp-hpux11.11 with no regressions. Committed to active branches and trunk. Dave -- John David Anglin dave.ang...@bell.net
2015-09-12 John David Anglin <dang...@gcc.gnu.org> * config/pa/pa.c (pa_output_move_double): Enhance to handle HIGH CONSTANT_P operands. Index: config/pa/pa.c =================================================================== --- config/pa/pa.c (revision 226978) +++ config/pa/pa.c (working copy) @@ -2464,6 +2464,7 @@ enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx addreg0 = 0, addreg1 = 0; + int highonly = 0; /* First classify both operands. */ @@ -2674,7 +2675,14 @@ else if (optype1 == OFFSOP) latehalf[1] = adjust_address_nv (operands[1], SImode, 4); else if (optype1 == CNSTOP) - split_double (operands[1], &operands[1], &latehalf[1]); + { + if (GET_CODE (operands[1]) == HIGH) + { + operands[1] = XEXP (operands[1], 0); + highonly = 1; + } + split_double (operands[1], &operands[1], &latehalf[1]); + } else latehalf[1] = operands[1]; @@ -2727,8 +2735,11 @@ if (addreg1) output_asm_insn ("ldo 4(%0),%0", &addreg1); - /* Do that word. */ - output_asm_insn (pa_singlemove_string (latehalf), latehalf); + /* Do high-numbered word. */ + if (highonly) + output_asm_insn ("ldil L'%1,%0", latehalf); + else + output_asm_insn (pa_singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0)