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)

Reply via email to