2005-07-08  Jakub Jelinek  <jakub@redhat.com>

	* config/ia64/ia64.h (FRAME_GROWS_DOWNWARD): Define to 1 if
	-fstack-protect.
	* config/ia64/ia64.c (ia64_compute_frame_size): Make sure
	size is a multiple of 16 if FRAME_GROWS_DOWNWARD.
	(ia64_initial_elimination_offset): Support FRAME_GROWS_DOWNWARD
	layout.
	* config/ia64/linux.h (TARGET_LIBC_PROVIDES_SSP): Define.
	* config/ia64/ia64.md (stack_protect_set, stack_protect_test): New
	expanders.

Index: gcc/config/ia64/linux.h
===================================================================
*** gcc/config/ia64/linux.h.orig	2009-04-29 17:22:55.000000000 +0200
--- gcc/config/ia64/linux.h	2010-01-12 14:31:19.000000000 +0100
*************** do {						\
*** 84,89 ****
--- 84,94 ----
  
  #define MD_UNWIND_SUPPORT "config/ia64/linux-unwind.h"
  
+ #ifdef TARGET_LIBC_PROVIDES_SSP
+ /* IA-64 glibc provides __stack_chk_guard in [r13-8].  */
+ #define TARGET_THREAD_SSP_OFFSET	-8
+ #endif
+ 
  /* Put all *tf routines in libgcc.  */
  #undef LIBGCC2_HAS_TF_MODE
  #define LIBGCC2_HAS_TF_MODE 1
Index: gcc/config/ia64/ia64.c
===================================================================
*** gcc/config/ia64/ia64.c.orig	2009-12-14 00:18:26.000000000 +0100
--- gcc/config/ia64/ia64.c	2010-01-12 14:34:21.000000000 +0100
*************** ia64_compute_frame_size (HOST_WIDE_INT s
*** 2727,2732 ****
--- 2727,2735 ----
    else
      pretend_args_size = crtl->args.pretend_args_size;
  
+   if (FRAME_GROWS_DOWNWARD)
+     size = IA64_STACK_ALIGN (size);
+ 
    total_size = (spill_size + extra_spill_size + size + pretend_args_size
  		+ crtl->outgoing_args_size);
    total_size = IA64_STACK_ALIGN (total_size);
*************** ia64_can_eliminate (const int from ATTRI
*** 2759,2790 ****
  HOST_WIDE_INT
  ia64_initial_elimination_offset (int from, int to)
  {
!   HOST_WIDE_INT offset;
  
!   ia64_compute_frame_size (get_frame_size ());
    switch (from)
      {
      case FRAME_POINTER_REGNUM:
!       switch (to)
! 	{
! 	case HARD_FRAME_POINTER_REGNUM:
! 	  if (current_function_is_leaf)
! 	    offset = -current_frame_info.total_size;
! 	  else
! 	    offset = -(current_frame_info.total_size
! 		       - crtl->outgoing_args_size - 16);
! 	  break;
! 
! 	case STACK_POINTER_REGNUM:
! 	  if (current_function_is_leaf)
! 	    offset = 0;
! 	  else
! 	    offset = 16 + crtl->outgoing_args_size;
! 	  break;
! 
! 	default:
! 	  gcc_unreachable ();
! 	}
        break;
  
      case ARG_POINTER_REGNUM:
--- 2762,2780 ----
  HOST_WIDE_INT
  ia64_initial_elimination_offset (int from, int to)
  {
!   HOST_WIDE_INT offset, size = get_frame_size ();
  
!   ia64_compute_frame_size (size);
    switch (from)
      {
      case FRAME_POINTER_REGNUM:
!       offset = FRAME_GROWS_DOWNWARD ? IA64_STACK_ALIGN (size) : 0;
!       if (!current_function_is_leaf)
! 	offset += 16 + crtl->outgoing_args_size;
!       if (to == HARD_FRAME_POINTER_REGNUM)
! 	offset -= current_frame_info.total_size;
!       else
! 	gcc_assert (to == STACK_POINTER_REGNUM);
        break;
  
      case ARG_POINTER_REGNUM:
Index: gcc/config/ia64/ia64.md
===================================================================
*** gcc/config/ia64/ia64.md.orig	2009-12-14 00:18:26.000000000 +0100
--- gcc/config/ia64/ia64.md	2010-01-12 14:31:19.000000000 +0100
***************
*** 5176,5181 ****
--- 5176,5218 ----
   "mov %0 = ip"
    [(set_attr "itanium_class" "frbr")])
  
+ ;;
+ ;; Stack guard expanders
+ 
+ (define_expand "stack_protect_set"
+   [(set (match_operand 0 "memory_operand" "")
+         (match_operand 1 "memory_operand" ""))]
+   ""
+ {
+ #ifdef TARGET_THREAD_SSP_OFFSET
+   rtx thread_pointer_rtx = gen_rtx_REG (Pmode, 13);
+   rtx canary = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, thread_pointer_rtx,
+ 					GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+   MEM_VOLATILE_P (canary) = MEM_VOLATILE_P (operands[1]);
+   operands[1] = canary;
+ #endif
+   emit_move_insn (operands[0], operands[1]);
+   DONE;
+ })
+ 
+ (define_expand "stack_protect_test"
+   [(match_operand 0 "memory_operand" "")
+    (match_operand 1 "memory_operand" "")
+    (match_operand 2 "" "")]
+   ""
+ {
+ #ifdef TARGET_THREAD_SSP_OFFSET
+   rtx thread_pointer_rtx = gen_rtx_REG (Pmode, 13);
+   rtx canary = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, thread_pointer_rtx,
+ 					GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+   MEM_VOLATILE_P (canary) = MEM_VOLATILE_P (operands[1]);
+   operands[1] = canary;
+ #endif
+   emit_cmp_and_jump_insns (operands[0], operands[1], EQ, NULL_RTX,
+ 			   ptr_mode, 1, operands[2]);
+   DONE;
+ })
+ 
  ;; Vector operations
  (include "vect.md")
  ;; Atomic operations
Index: gcc/config/ia64/ia64.h
===================================================================
*** gcc/config/ia64/ia64.h.orig	2009-09-25 14:31:44.000000000 +0200
--- gcc/config/ia64/ia64.h	2010-01-12 14:31:19.000000000 +0100
*************** enum reg_class
*** 927,933 ****
  
  /* Define this macro to nonzero if the addresses of local variable slots
     are at negative offsets from the frame pointer.  */
! #define FRAME_GROWS_DOWNWARD 0
  
  /* Offset from the frame pointer to the first local variable slot to
     be allocated.  */
--- 927,933 ----
  
  /* Define this macro to nonzero if the addresses of local variable slots
     are at negative offsets from the frame pointer.  */
! #define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0)
  
  /* Offset from the frame pointer to the first local variable slot to
     be allocated.  */
