ia64 reload failure

Richard Henderson rth@cygnus.com
Mon Jul 17 15:33:00 GMT 2000


Given

struct
{
  int offset;
  struct slot
  {
    int field[6];
  }
  slot[4];
} s;

int
x ()
{
  int toggle = 0;
  int r = s.slot[0].field[!toggle];
  return r;
}

we'd generate incorrect code at -O0, by emitting `movl r14 = s#',
which is wrong since IA-64 code is by default PIC.

This came from having a register be REG_EQUIV to (symbol_ref "s")
and the pseudo used across two basic blocks.  Reload would elide
the spill/fill and emit `(set (reg 14) (symbol_ref "s"))' without
calling gen_movdi again.

There are a number of possible fixes.  The one I'm guessing leads
to the most efficient output for IA-64 is to provisionally accept
such instructions and then split them after reload.

I'll probably check in the test case.  Even though it doesn't fail
under Linux (due to a number of things not worth discussing here),
it does fail under other IA-64 operating systems.


r~


2000-07-17  Richard Henderson  <rth@cygnus.com>

        * config/ia64/ia64.md (movdi): Split out load address code.
        New post-reload splitter for symbolic operands.
        (movdi_internal): Abort if we didn't split symbolic operands
        when we should have.
        * config/ia64/ia64.c (ia64_expand_load_address): New, from movdi bits.
        (ia64_reorg): Split insns when not optimizing.
        * config/ia64/ia64-protos.h (ia64_expand_load_address): Declare.

Index: ia64-protos.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64-protos.h,v
retrieving revision 1.15
diff -c -p -d -r1.15 ia64-protos.h
*** ia64-protos.h	2000/07/15 20:30:46	1.15
--- ia64-protos.h	2000/07/17 21:55:41
*************** extern int call_multiple_values_operatio
*** 52,57 ****
--- 52,58 ----
  extern int predicate_operator PARAMS((rtx, enum machine_mode));
  extern int ia64_move_ok PARAMS((rtx, rtx));
  
+ extern void ia64_expand_load_address PARAMS((rtx, rtx));
  extern void ia64_expand_fetch_and_op PARAMS ((enum fetchop_code,
  					      enum machine_mode, rtx []));
  extern void ia64_expand_op_and_fetch PARAMS ((enum fetchop_code,
Index: ia64.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 ia64.c
*** ia64.c	2000/07/15 20:30:46	1.70
--- ia64.c	2000/07/17 21:55:41
*************** predicate_operator (op, mode)
*** 542,548 ****
    return ((GET_MODE (op) == mode || mode == VOIDmode)
  	  && (code == EQ || code == NE));
  }
! 
  /* Return 1 if the operands of a move are ok.  */
  
  int
--- 542,548 ----
    return ((GET_MODE (op) == mode || mode == VOIDmode)
  	  && (code == EQ || code == NE));
  }
! 
  /* Return 1 if the operands of a move are ok.  */
  
  int
*************** ia64_move_ok (dst, src)
*** 566,571 ****
--- 566,618 ----
    else
      return GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src);
  }
+ 
+ /* Expand a symbolic constant load.  */
+ /* ??? Should generalize this, so that we can also support 32 bit pointers.  */
+ 
+ void
+ ia64_expand_load_address (dest, src)
+       rtx dest, src;
+ {
+   rtx temp;
+ 
+   /* The destination could be a MEM during initial rtl generation,
+      which isn't a valid destination for the PIC load address patterns.  */
+   if (! register_operand (dest, DImode))
+     temp = gen_reg_rtx (DImode);
+   else
+     temp = dest;
+ 
+   if (TARGET_AUTO_PIC)
+     emit_insn (gen_load_gprel64 (temp, src));
+   else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src))
+     emit_insn (gen_load_fptr (temp, src));
+   else if (sdata_symbolic_operand (src, DImode))
+     emit_insn (gen_load_gprel (temp, src));
+   else if (GET_CODE (src) == CONST
+ 	   && GET_CODE (XEXP (src, 0)) == PLUS
+ 	   && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT
+ 	   && (INTVAL (XEXP (XEXP (src, 0), 1)) & 0x1fff) != 0)
+     {
+       rtx subtarget = no_new_pseudos ? temp : gen_reg_rtx (DImode);
+       rtx sym = XEXP (XEXP (src, 0), 0);
+       HOST_WIDE_INT ofs, hi, lo;
+ 
+       /* Split the offset into a sign extended 14-bit low part
+ 	 and a complementary high part.  */
+       ofs = INTVAL (XEXP (XEXP (src, 0), 1));
+       lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000;
+       hi = ofs - lo;
+ 
+       emit_insn (gen_load_symptr (subtarget, plus_constant (sym, hi)));
+       emit_insn (gen_adddi3 (temp, subtarget, GEN_INT (lo)));
+     }
+   else
+     emit_insn (gen_load_symptr (temp, src));
+ 
+   if (temp != dest)
+     emit_move_insn (dest, temp);
+ }
  
  /* Begin the assembly file.  */
  
*************** void
*** 3016,3021 ****
--- 3063,3072 ----
  ia64_reorg (insns)
       rtx insns;
  {
+   /* If optimizing, we'll have split before scheduling.  */
+   if (optimize == 0)
+     split_all_insns (0);
+ 
    emit_predicate_relation_info (insns);
    emit_insn_group_barriers (insns);
  }
Index: ia64.md
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64.md,v
retrieving revision 1.68
diff -c -p -d -r1.68 ia64.md
*** ia64.md	2000/07/15 20:30:46	1.68
--- ia64.md	2000/07/17 21:55:41
***************
*** 247,299 ****
    ""
    "
  {
-   /* ??? Should generalize this, so that we can also support 32 bit
-      pointers.  */
    if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
      {
!       rtx temp;
! 
!       /* Operand[0] could be a MEM, which isn't a valid destination for the
! 	 PIC load address patterns.  */
!       if (! register_operand (operands[0], DImode))
! 	temp = gen_reg_rtx (DImode);
!       else
! 	temp = operands[0];
! 
!       if (TARGET_AUTO_PIC)
! 	emit_insn (gen_load_gprel64 (temp, operands[1]));
!       else if (GET_CODE (operands[1]) == SYMBOL_REF
! 	       && SYMBOL_REF_FLAG (operands[1]))
! 	emit_insn (gen_load_fptr (temp, operands[1]));
!       else if (sdata_symbolic_operand (operands[1], DImode))
! 	emit_insn (gen_load_gprel (temp, operands[1]));
!       else if (GET_CODE (operands[1]) == CONST
! 	       && GET_CODE (XEXP (operands[1], 0)) == PLUS
! 	       && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
! 	       && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x1fff) != 0)
! 	{
! 	  rtx subtarget = no_new_pseudos ? temp : gen_reg_rtx (DImode);
! 	  rtx sym = XEXP (XEXP (operands[1], 0), 0);
! 	  HOST_WIDE_INT ofs, hi, lo;
! 
! 	  /* Split the offset into a sign extended 14-bit low part
! 	     and a complementary high part.  */
! 	  ofs = INTVAL (XEXP (XEXP (operands[1], 0), 1));
! 	  lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000;
! 	  hi = ofs - lo;
! 	
! 	  emit_insn (gen_load_symptr (subtarget, plus_constant (sym, hi)));
! 	  emit_insn (gen_adddi3 (temp, subtarget, GEN_INT (lo)));
! 	}
!       else
! 	emit_insn (gen_load_symptr (temp, operands[1]));
! 
!       if (temp == operands[0])
! 	DONE;
! 
!       operands[1] = temp;
      }
- 
    if (! reload_in_progress && ! reload_completed
        && ! ia64_move_ok (operands[0], operands[1]))
      operands[1] = force_reg (DImode, operands[1]);
--- 247,257 ----
    ""
    "
  {
    if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
      {
!       ia64_expand_load_address (operands[0], operands[1]);
!       DONE;
      }
    if (! reload_in_progress && ! reload_completed
        && ! ia64_move_ok (operands[0], operands[1]))
      operands[1] = force_reg (DImode, operands[1]);
***************
*** 303,322 ****
    [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r, m,r,*f,*f,*f,Q, r,*b")
  	(match_operand:DI 1 "move_operand"         "rO,J,i,m,rO,*f,rO,*f,Q,*f,*b,rO"))]
    "ia64_move_ok (operands[0], operands[1])"
!   "@
!   mov %0 = %r1
!   addl %0 = %1, r0
!   movl %0 = %1
!   ld8%O1 %0 = %1%P1
!   st8%Q0 %0 = %r1%P0
!   getf.sig %0 = %1
!   setf.sig %0 = %r1
!   mov %0 = %1
!   ldf8 %0 = %1%P1
!   stf8 %0 = %1%P0
!   mov %0 = %1
!   mov %0 = %r1"
    [(set_attr "type" "A,A,L,M,M,M,M,F,M,M,I,I")])
  
  (define_expand "load_fptr"
    [(set (match_dup 2)
--- 261,312 ----
    [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r, m,r,*f,*f,*f,Q, r,*b")
  	(match_operand:DI 1 "move_operand"         "rO,J,i,m,rO,*f,rO,*f,Q,*f,*b,rO"))]
    "ia64_move_ok (operands[0], operands[1])"
!   "*
! {
!   static const char * const alt[] = {
!     \"mov %0 = %r1\",
!     \"addl %0 = %1, r0\",
!     \"movl %0 = %1\",
!     \"ld8%O1 %0 = %1%P1\",
!     \"st8%Q0 %0 = %r1%P0\",
!     \"getf.sig %0 = %1\",
!     \"setf.sig %0 = %r1\",
!     \"mov %0 = %1\",
!     \"ldf8 %0 = %1%P1\",
!     \"stf8 %0 = %1%P0\",
!     \"mov %0 = %1\",
!     \"mov %0 = %r1\"
!   };
! 
!   /* We use 'i' for alternative 2 despite possible PIC problems.
! 
!      If we define LEGITIMATE_CONSTANT_P such that symbols are not
!      allowed, then the compiler dumps the data into constant memory
!      instead of letting us read the values from the GOT.  Similarly
!      if we use 'n' instead of 'i'.
! 
!      Instead, we allow such insns through reload and then split them
!      afterward (even without optimization).  Therefore, we should
!      never get so far with a symbolic operand.  */
! 
!   if (which_alternative == 2 && ! TARGET_NO_PIC
!       && symbolic_operand (operands[1], VOIDmode))
!     abort ();
! 
!   return alt[which_alternative];
! }"
    [(set_attr "type" "A,A,L,M,M,M,M,F,M,M,I,I")])
+ 
+ (define_split
+   [(set (match_operand:DI 0 "register_operand" "")
+ 	(match_operand:DI 1 "symbolic_operand" ""))]
+   "reload_completed && ! TARGET_NO_PIC"
+   [(const_int 0)]
+   "
+ {
+   ia64_expand_load_address (operands[0], operands[1]);
+   DONE;
+ }")
  
  (define_expand "load_fptr"
    [(set (match_dup 2)


More information about the Gcc-patches mailing list