Add partial support for IA-64 unwind sections.
authorAndrew MacLeod <amacleod@cygnus.com>
Tue, 25 Apr 2000 23:16:20 +0000 (23:16 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Tue, 25 Apr 2000 23:16:20 +0000 (16:16 -0700)
* config/ia64/crtbegin.asm: Add IA-64 unwind support.  Correct alloc
and gp save/restore problems.
* config/ia64/crtend.asm: Add IA-64 unwind support.
* config/ia64/ia64.c (ia64_compute_frame_size): Don't include pr_size
in fr_pad_size calculation.
...

Co-Authored-By: Andrew Haley <aph@cygnus.com>
Co-Authored-By: Jim Wilson <wilson@cygnus.com>
From-SVN: r33424

gcc/ChangeLog
gcc/config/ia64/crtbegin.asm
gcc/config/ia64/crtend.asm
gcc/config/ia64/ia64.c
gcc/config/ia64/ia64.h
gcc/config/ia64/ia64.md

index 89d3dd43f593972dd24037e3b92ab22dcd562c30..9ec11162b96e43131356dea41ef9eaf308e328f3 100644 (file)
@@ -1,3 +1,33 @@
+Tue Apr 25 16:16:04 2000  Andrew MacLeod  <amacleod@cygnus.com>
+                         Jim Wilson  <wilson@cygnus.com>
+                         Andrew Haley  <aph@cygnus.com>
+       
+       * config/ia64/crtbegin.asm: Add IA-64 unwind support.  Correct alloc
+       and gp save/restore problems.
+       * config/ia64/crtend.asm: Add IA-64 unwind support.
+       * config/ia64/ia64.c (ia64_compute_frame_size): Don't include pr_size
+       in fr_pad_size calculation.
+       (save_restore_insns): Move PR save area.  Correct uses of
+       RTX_FRAME_RELATED_P.
+       (ia64_expand_prologue): Mark alloc with RTX_FRAME_RELATED_P.
+       (ia64_expand_epilogue): Add eh_epilogue support.
+       (ia64_function_prologue): Emit .prologue directive.
+       (ia64_init_machine_status, ia64_mark_machine_status): New functions.
+       (ia64_override_options): Set init_machine_status and
+       mark_machine_status.
+       (rtx_needs_barrier): Handle bsp reads and writes.
+       (spill_offset, sp_offset, spill_offset_emitted, tmp_reg, tmp_saved):
+       New static variables.
+       (process_set, process_for_unwind_directive): New functions.
+       * config/ia64/ia64.h (ASM_OUTPUT_XDATA_CHAR, ASM_OUTPUT_XDATA_SHORT,
+       ASM_OUTPUT_XDATA_INT, ASM_OUTPUT_XDATA_DOUBLE_INT, ASM_OUTPUT_EH_CHAR,
+       ASM_OUTPUT_EH_SHORT, ASM_OUTPUT_EH_INT, ASM_OUTPUT_EH_DOUBLE_INT): New
+       macros.
+       (EH_FRAME_SECTION_ASM_OP): Define to IA_64.unwind section.
+       (IA64_UNWIND_INFO, HANDLER_SECTION, IA64_UNWIND_EMIT): Define.
+       (struct machine_function): Define.
+       * config/ia64/ia64.md (bsp_value, set_bsp, eh_epilogue): New patterns.
+       
 2000-04-25  Bruce Korb  <bkorb@gnu.org>
 
        * fixinc/Makefile.in: make the removal of old programs more
index b77ad986fc6e284edfcdfe507b885ed477c62924..d44df5b16106be114530aba60f29a34b7490e30c 100644 (file)
@@ -26,12 +26,17 @@ __CTOR_LIST__:
 __DTOR_LIST__:
        data8   -1
 
+.section .IA_64.unwind
+__EH_FRAME_BEGIN__:
+
 .section .sdata
+5:     data8   @segrel(6f)
        .type dtor_ptr#,@object
        .size dtor_ptr#,8
 dtor_ptr:
        data8   __DTOR_LIST__# + 8
 
+/* A handle for __cxa_finalize to manage c++ local destructors.  */
        .global __dso_handle#
        .type __dso_handle#,@object
        .size __dso_handle#,8
@@ -45,6 +50,16 @@ __dso_handle:
        data8   0
 #endif
 
+/* The frame object.  */
+/* ??? How can we rationally keep this size correct?  */
+
+.section .bss
+       .type frame_object#,@object
+       .size frame_object#,56
+       .align 8
+frame_object:
+       .zero 56
+
 /*
  * Fragment of the ELF _fini routine that invokes our dtor cleanup.
  *
@@ -65,38 +80,55 @@ __dso_handle:
          ;;
        }
 
-.text
+/*
+ * Fragment of the ELF _init routine that sets up the frame info.
+ */
+
+.section .init,"ax","progbits"
+       { .mfb
+         st8 [r12] = gp, -16
+         br.call.sptk.many b0 = __do_frame_setup#
+         ;;
+       }
+       { .mmi
+         adds r12 = 16, r12
+         ;;
+         ld8 gp = [r12]
+         ;;
+       }
 
+.section .text
        .align  16
        .proc   __do_global_dtors_aux#
-
 __do_global_dtors_aux:
 #ifndef SHARED
        { .mii
-         alloc loc2 = ar.pfs, 0, 3, 0, 0
+         alloc loc3 = ar.pfs, 0, 4, 1, 0
          addl loc0 = @gprel(dtor_ptr#), gp
          mov loc1 = b0
        }
+       mov loc2 = gp
 #else
        /*
                if (__cxa_finalize)
                  __cxa_finalize(__dso_handle)
        */
        { .mii
-         alloc loc2 = ar.pfs, 1, 3, 0, 0
+         alloc loc3 = ar.pfs, 0, 4, 1, 0
          addl loc0 = @gprel(dtor_ptr#), gp
          addl r16 = @ltoff(@fptr(__cxa_finalize#)), gp
          ;;
        }
+       mov loc2 = gp
        { .mmi
          ld8 r16 = [r16]
          ;;
-         addl r32 = @ltoff(__dso_handle#), gp
+         addl out0 = @ltoff(__dso_handle#), gp
          cmp.ne p7, p0 = r0, r16
          ;;
        }
        { .mmi
-         ld8 r32 = [r32]
+         ld8 out0 = [out0]
 (p7)     ld8 r18 = [r16], 8
          mov loc1 = b0
          ;;
@@ -138,10 +170,37 @@ __do_global_dtors_aux:
        { .mfb
          cmp.ne p6, p0 = r0, r16
 (p6)     br.cond.sptk.few 0b
+       }
+       mov gp = loc2
+       ;;
+       /*
+               if (__deregister_frame_info)
+                 __deregister_frame_info(__EH_FRAME_BEGIN__)
+       */
+       { .mii
+         addl r16 = @ltoff(@fptr(__deregister_frame_info#)), gp
+         addl out0 = @ltoff(__EH_FRAME_BEGIN__#), gp
+         ;;
+       }
+       { .mmi
+         ld8 r16 = [r16]
+         ld8 out0 = [out0]
+         ;;
+       }
+       { .mmi
+         cmp.ne p7, p0 = r0, r16
+         ;;
+(p7)     ld8 r18 = [r16], 8
+         ;;
+       }
+       { .mib
+(p7)     ld8 gp = [r16]
+(p7)     mov b6 = r18
+(p7)     br.call.sptk.many b0 = b6
        }
        { .mii
          mov b0 = loc1
-         mov ar.pfs = loc2
+         mov ar.pfs = loc3
        }
        { .bbb
          br.ret.sptk.many b0
@@ -149,6 +208,61 @@ __do_global_dtors_aux:
        }
        .endp   __do_global_dtors_aux#
 
+       .proc   __do_frame_setup#
+__do_frame_setup:
+       /*
+               if (__register_frame_info)
+                 __register_frame_info(__EH_FRAME_BEGIN__)
+       */
+       { .mii
+         alloc loc3 = ar.pfs, 0, 4, 2, 0
+         addl r16 = @ltoff(@fptr(__register_frame_info#)), gp
+         addl out0 = @ltoff(__EH_FRAME_BEGIN__#), gp
+         ;;
+       }
+       addl out1 = @ltoff(frame_object#), gp
+       ;;
+       /* frame_object.pc_base = segment_base_offset;
+             pc_base is at offset 0 within frame_object.  */
+6:
+       mov loc0 = ip
+       addl loc1 = @gprel(5b), gp
+       ;;
+       ld8 loc1 = [loc1]
+       ld8 out1 = [out1]
+       ;;
+       sub loc2 = loc0, loc1
+       ;;
+       st8 [out1] = loc2
+       { .mmi
+         ld8 r16 = [r16]
+         ld8 out0 = [out0]  
+         mov loc0 = b0
+         ;;
+       }
+       { .mmi
+         cmp.ne p7, p0 = r0, r16
+         ;;
+(p7)     ld8 r18 = [r16], 8
+         ;;
+       }
+       { .mib
+(p7)     ld8 gp = [r16]
+(p7)     mov b6 = r18
+(p7)     br.call.sptk.many b0 = b6
+       }
+       { .mii
+         mov b0 = loc0
+         mov ar.pfs = loc3
+       }
+       { .bbb
+         br.ret.sptk.many b0
+         ;;
+       }
+       .endp   __do_frame_setup#
+
 #ifdef SHARED
 .weak __cxa_finalize#
 #endif
+.weak __deregister_frame_info#
+.weak __register_frame_info#
index 3da0f96e7483836afad26dda9a37644fc5b0954d..208c469c9dbeb680a536a36e2c3858133388ba7e 100644 (file)
@@ -26,6 +26,10 @@ __CTOR_END__:
 __DTOR_END__:
        data8   0
 
+.section .IA_64.unwind
+__EH_FRAME_END__:
+       data8   -1
+
 /*
  * Fragment of the ELF _init routine that invokes our dtor cleanup.
  *
index 362c8583e9ca0c646508b0b61d0e0cb51a524624..dbc89d7dfb77dec5393f27b10c7244bc1f843755 100644 (file)
@@ -567,7 +567,7 @@ ia64_compute_frame_size (size)
   /* The FR save area needs to be 16-byte aligned.  */
   if (fr_size)
     {
-      tmp = (size + fr_size + pr_size + br_size);
+      tmp = (size + fr_size + br_size);
       fr_pad_size = IA64_STACK_ALIGN (tmp) - tmp;
     }
   else
@@ -653,14 +653,36 @@ save_restore_insns (save_p)
        {
          offset_rtx = tmp_reg;
          insn = emit_insn (gen_movdi (tmp_reg, GEN_INT (offset)));
-         RTX_FRAME_RELATED_P (insn) = 1;
+         if (save_p)
+           RTX_FRAME_RELATED_P (insn) = 1;
        }
       insn = emit_insn (gen_adddi3 (tmp_reg,
                                    (frame_pointer_needed ? frame_pointer_rtx
                                     : stack_pointer_rtx),
                                    offset_rtx));
-      RTX_FRAME_RELATED_P (insn) = 1;
+      if (save_p)
+       RTX_FRAME_RELATED_P (insn) = 1;
 
+      /* If one is used, we save/restore all of them.  */
+      for (regno = PR_REG (0); regno <= PR_REG (63); regno++)
+       if (TEST_HARD_REG_BIT (current_frame_info.mask, regno))
+         {
+           rtx mem = gen_rtx_MEM (DImode, tmp_post_inc);
+           if (save_p)
+             {
+               insn = emit_insn (gen_pr_spill (tmp2_reg));
+               RTX_FRAME_RELATED_P (insn) = 1;
+               insn = emit_insn (gen_movdi (mem, tmp2_reg));
+               RTX_FRAME_RELATED_P (insn) = 1;
+             }
+           else
+             {
+               insn = emit_insn (gen_movdi (tmp2_reg, mem));
+               insn = emit_insn (gen_pr_restore (tmp2_reg));
+             }
+           break;
+         }
+               
       /* Must save/restore ar.unat if any GR is spilled/restored.  */
       if (current_frame_info.gr_size != 0
          || current_function_varargs || current_function_stdarg)
@@ -669,18 +691,21 @@ save_restore_insns (save_p)
          if (save_p)
            {
              insn = emit_insn (gen_unat_spill (tmp2_reg));
-             RTX_FRAME_RELATED_P (insn) = 1;
+             if (save_p)
+               RTX_FRAME_RELATED_P (insn) = 1;
              insn = emit_insn (gen_movdi (mem, tmp2_reg));
-             RTX_FRAME_RELATED_P (insn) = 1;
+             if (save_p)
+               RTX_FRAME_RELATED_P (insn) = 1;
            }
          else
            {
              insn = emit_insn (gen_movdi (tmp2_reg, mem));
-             RTX_FRAME_RELATED_P (insn) = 1;
+             if (save_p)
+               RTX_FRAME_RELATED_P (insn) = 1;
              /* The restore happens after the last ld8.fill instruction.  */
            }
        }
-
+       
       for (regno = GR_REG (0); regno <= GR_REG (127); regno++)
        if (TEST_HARD_REG_BIT (current_frame_info.mask, regno))
          {
@@ -691,7 +716,8 @@ save_restore_insns (save_p)
            else
              insn = emit_insn (gen_gr_restore (gen_rtx_REG (DImode, regno),
                                                mem));
-           RTX_FRAME_RELATED_P (insn) = 1;
+           if (save_p)
+             RTX_FRAME_RELATED_P (insn) = 1;
          }
 
       /* Now restore the unat register if necessary.  */
@@ -710,31 +736,10 @@ save_restore_insns (save_p)
            else
              insn = emit_insn (gen_fr_restore (gen_rtx_REG (XFmode, regno),
                                                mem));
-           RTX_FRAME_RELATED_P (insn) = 1;
-         }
-
-      /* If one is used, we save/restore all of them.  */
-      for (regno = PR_REG (0); regno <= PR_REG (63); regno++)
-       if (TEST_HARD_REG_BIT (current_frame_info.mask, regno))
-         {
-           rtx mem = gen_rtx_MEM (DImode, tmp_post_inc);
            if (save_p)
-             {
-               insn = emit_insn (gen_pr_spill (tmp2_reg));
-               RTX_FRAME_RELATED_P (insn) = 1;
-               insn = emit_insn (gen_movdi (mem, tmp2_reg));
-               RTX_FRAME_RELATED_P (insn) = 1;
-             }
-           else
-             {
-               insn = emit_insn (gen_movdi (tmp2_reg, mem));
-               RTX_FRAME_RELATED_P (insn) = 1;
-               insn = emit_insn (gen_pr_restore (tmp2_reg));
-               RTX_FRAME_RELATED_P (insn) = 1;
-             }
-           break;
+             RTX_FRAME_RELATED_P (insn) = 1;
          }
-                                            
+                    
       for (regno = BR_REG (0); regno <= BR_REG (7); regno++)
        if (TEST_HARD_REG_BIT (current_frame_info.mask, regno))
          {
@@ -752,9 +757,11 @@ save_restore_insns (save_p)
              }
 
            insn = emit_insn (gen_movdi (tmp2_reg, src));
-           RTX_FRAME_RELATED_P (insn) = 1;
+           if (save_p)
+             RTX_FRAME_RELATED_P (insn) = 1;
            insn = emit_insn (gen_movdi (dest, tmp2_reg));
-           RTX_FRAME_RELATED_P (insn) = 1;
+           if (save_p)
+             RTX_FRAME_RELATED_P (insn) = 1;
          }
     }
 }
@@ -933,9 +940,10 @@ ia64_expand_prologue ()
       ia64_need_regstk = 0;
       ia64_arpfs_regno = LOC_REG (locals - 1);
 
-      emit_insn (gen_alloc (gen_rtx_REG (DImode, ia64_arpfs_regno),
-                           GEN_INT (inputs), GEN_INT (locals),
-                           GEN_INT (outputs), GEN_INT (rotates)));
+      insn = emit_insn (gen_alloc (gen_rtx_REG (DImode, ia64_arpfs_regno),
+                                  GEN_INT (inputs), GEN_INT (locals),
+                                  GEN_INT (outputs), GEN_INT (rotates)));
+      RTX_FRAME_RELATED_P (insn) = 1;
 
       /* Emit a save of BR_REG (0) if we call other functions.
         Do this even if this function doesn't return, as EH
@@ -1020,32 +1028,38 @@ ia64_expand_epilogue ()
      pointer updates anti-dependent on them.  */
   emit_insn (gen_blockage ());
 
-  if (frame_pointer_needed)
+  if (cfun->machine->ia64_eh_epilogue_sp == NULL_RTX)
     {
-      /* If there is a frame pointer, then we need to make the stack pointer
-        restore depend on the frame pointer, so that the stack pointer
-        restore won't be moved up past fp-relative loads from the frame.  */
-      emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
-                                               hard_frame_pointer_rtx));
-    }
-  else
-    {
-      int frame_size = current_frame_info.total_size;
-      rtx offset;
+    if (frame_pointer_needed)
+      {
+       /* If there is a frame pointer, then we need to make the stack pointer
+          restore depend on the frame pointer, so that the stack pointer
+          restore won't be moved up past fp-relative loads from the frame.  */
+       emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
+                                                 hard_frame_pointer_rtx));
+      }
+    else
+      {
+       int frame_size = current_frame_info.total_size;
+       rtx offset;
 
-      if (frame_size != 0)
-       {
-         if (CONST_OK_FOR_I (frame_size))
-           offset = GEN_INT (frame_size);
-         else
-           {
-             offset = gen_rtx_REG (DImode, GR_REG (2));
-             emit_insn (gen_movdi (offset, GEN_INT (frame_size)));
-           }
-         emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                offset));
-       }
+       if (frame_size != 0)
+         {
+           if (CONST_OK_FOR_I (frame_size))
+             offset = GEN_INT (frame_size);
+           else
+             {
+               offset = gen_rtx_REG (DImode, GR_REG (2));
+               emit_insn (gen_movdi (offset, GEN_INT (frame_size)));
+             }
+           emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  offset));
+         }
+      }
     }
+    /* Return via eh_epilogue, so we already have our new stack pointer.  */
+  else
+    emit_insn (gen_movdi (stack_pointer_rtx, cfun->machine->ia64_eh_epilogue_sp));
 
   if (ia64_arpfs_regno)
     emit_insn (gen_pfs_restore (gen_rtx_REG (DImode, ia64_arpfs_regno)));
@@ -1054,6 +1068,11 @@ ia64_expand_epilogue ()
     emit_move_insn (gen_rtx_REG (DImode, BR_REG (0)),
                    gen_rtx_REG (DImode, ia64_rp_regno));
 
+  if (cfun->machine->ia64_eh_epilogue_bsp != NULL_RTX)
+    {
+      /* We have to restore the bsp.  */
+      emit_insn (gen_set_bsp (cfun->machine->ia64_eh_epilogue_bsp));
+    }
   emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0))));
 }
 
@@ -1064,10 +1083,39 @@ ia64_function_prologue (file, size)
      FILE *file;
      int size;
 {
+  rtx insn;
   if (ia64_need_regstk)
     fprintf (file, "\t.regstk %d, 0, 0, 0\n", ia64_input_regs);
 
-  /* ??? Emit .body directive.  GNU as ignores .body currently.  */
+  if (!flag_unwind_tables && (!flag_exceptions || exceptions_via_longjmp))
+    return;
+
+  /* Emit the .prologue directive. in order to do this, we need to find
+     where the stack pointer is moved toa GR, if it is, and mark it.  */
+  
+  for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+    {
+      if (RTX_FRAME_RELATED_P (insn) && GET_CODE (insn) == INSN)
+        {
+         rtx pat = PATTERN (insn);
+         if (GET_CODE (pat) == SET)
+           {
+             rtx dest = SET_DEST (pat);
+             rtx src = SET_SRC (pat);
+             if (GET_CODE (src) == REG && REGNO (src) == STACK_POINTER_REGNUM
+                 && GET_CODE (dest) == REG)
+               {
+                 int reg = REGNO (dest);
+                 if (REGNO (dest) == FRAME_POINTER_REGNUM)
+                   reg = ia64_fp_regno;
+                 fprintf (file, "\t.prologue 0x2, %d\n", reg);
+                 break;
+               }
+           }
+        }
+    }
+  if (insn == NULL_RTX)
+    fprintf (file, "\t.prologue\n");
 }
 
 /* Emit the function epilogue.  */
@@ -1987,6 +2035,23 @@ ia64_add_gc_roots ()
   ggc_add_rtx_root (&ia64_compare_op1, 1);
 }
 
+static void
+ia64_init_machine_status (p)
+     struct function *p;
+{
+  p->machine =
+    (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
+}
+
+static void
+ia64_mark_machine_status (p)
+     struct function *p;
+{
+  ggc_mark_rtx (p->machine->ia64_eh_epilogue_sp);
+  ggc_mark_rtx (p->machine->ia64_eh_epilogue_bsp);
+}
+
+
 /* Handle TARGET_OPTIONS switches.  */
 
 void
@@ -1997,6 +2062,9 @@ ia64_override_options ()
 
   ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE;
 
+  init_machine_status = ia64_init_machine_status;
+  mark_machine_status = ia64_mark_machine_status;
+
   ia64_add_gc_roots ();
 }
 \f
@@ -2445,6 +2513,9 @@ rtx_needs_barrier (x, flags, pred)
           break;
         case 19: /* fetchadd_acq */
           break;
+       case 20: /* mov = ar.bsp */
+          break;
+
        default:
          abort ();
        }
@@ -2485,6 +2556,10 @@ rtx_needs_barrier (x, flags, pred)
            need_barrier |= rws_access_reg (i, new_flags, pred);
          break;
 
+       case 5: /* set_bsp  */
+         need_barrier = 1;
+          break;
+
        default:
          abort ();
        }
@@ -2749,6 +2824,232 @@ ia64_encode_section_info (decl)
        }
     }
 }
+\f
+/* Output assmebly directives for prologue regions.  */
+
+static int spill_offset;
+static int sp_offset;
+static int spill_offset_emitted = 1;
+static rtx tmp_reg = NULL_RTX;
+static int tmp_saved = -1;
+
+
+/* This function processes a SET pattern looking for specific patterns
+   which result in emitting an assembly directive required for unwinding.  */
+static int
+process_set (asm_out_file, pat)
+     FILE *asm_out_file;
+     rtx pat;
+{
+  rtx src = SET_SRC (pat);
+  rtx dest = SET_DEST (pat);
+  static rtx frame_reg = NULL_RTX;
+  static int frame_size = 0;
+
+  /* Look for the ALLOC insn.  reg = alloc .... */
+  if (GET_CODE (src) == UNSPEC_VOLATILE && XINT (src, 1) == 0
+      && GET_CODE (dest) == REG && GR_REGNO_P (REGNO (dest)))
+    {
+      /* Assume this is a stack allocate insn.  */
+      fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", 
+              REGNO (dest) + ia64_input_regs);
+      return 1;
+    }
+
+  /* look for SP = .... */
+  if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM)
+    {
+      if (GET_CODE (src) == PLUS)
+        {
+         rtx op0 = XEXP (src, 0);
+         rtx op1 = XEXP (src, 1);
+         if (op0 == dest && GET_CODE (op1) == CONST_INT)
+           {
+             fprintf (asm_out_file, "\t.fframe %d\n", -INTVAL (op1));
+             frame_size = INTVAL (op1);
+             return 1;
+           }
+         else
+           if (op0 == dest && GET_CODE (op1) == REG)
+            {
+               fprintf (asm_out_file, "\t.vframe r%d\n", REGNO (op1));
+               frame_size = 0;
+               return 1;
+            }
+       }
+    }
+  /* Look for a frame offset.  */
+  if (GET_CODE (dest) == REG)
+    {
+      if (GET_CODE (src) == PLUS)
+        {
+         rtx op0 = XEXP (src, 0);
+         rtx op1 = XEXP (src, 1);
+         if (GET_CODE (op0) == REG && REGNO (op0) == FRAME_POINTER_REGNUM
+             && GET_CODE (op1) == CONST_INT)
+           {
+             sp_offset = -frame_size + INTVAL (op1);
+             spill_offset = INTVAL (op1);
+             spill_offset_emitted = 0;
+             frame_reg = dest;
+             /* We delay issuing the spill offset since we might
+                be saving non-spill things off this register,
+                thus adjusting its offset before a spill is seen.  */
+             return 1;
+           }
+       }
+    }
+
+  /* Register move we need to look at.  */
+  if (GET_CODE (dest) == REG && GET_CODE (src) == REG)
+    {
+      int regno = REGNO (src);
+      if (BR_REGNO_P (regno))
+        {
+         /* Saving return address pointer.  */
+         if (regno == BR_REG (0))
+           {
+             fprintf (asm_out_file, "\t.save rp, r%d\n", 
+                      REGNO (dest) + ia64_input_regs);
+             return 1;
+           }
+         /* If its br1 to br5, we copy them to temp regs, then save the
+            temp reg to memory next.  */
+         if (regno >= BR_REG (1) && regno <= BR_REG (5))
+           {
+             tmp_reg = dest;
+             tmp_saved = regno;
+             return 1;
+           }
+       }
+    }
+  /* Search for special reg moves.  */
+  if (GET_CODE (dest) == REG && GET_CODE (src) == UNSPEC)
+    {
+      int unspec_code = XINT (src, 1);
+      /* Copied to a temp register, save it until we see the temp
+        register stored.  */
+      if (unspec_code == 5 || unspec_code == 9)
+       {
+         tmp_reg = dest;
+         tmp_saved = unspec_code;
+         return 1;
+       }
+    }
+  if (GET_CODE (dest) == MEM && GET_CODE (XEXP (dest, 0)) == POST_INC 
+      && GET_CODE (XEXP (XEXP (dest, 0), 0)) == REG)
+    {
+      int spill_unspec = 0;
+      /* We adjust the spill_offset early, so we dont miss it later.  */
+      spill_offset += 8;  
+      sp_offset += 8;  
+      if (GET_CODE (src) == UNSPEC)
+       {
+         spill_unspec = XINT (src, 1);
+         /* 1 and 3 are unspecs for the GR and FR spills.  */
+         if (spill_unspec != 1 && spill_unspec != 3)
+           spill_unspec = 0;
+       }
+      /* ST8 or st8.spill insn.  */
+      if ((GET_CODE (src) == REG) || spill_unspec != 0)
+        {
+         int regno;
+         if (spill_unspec != 0)
+           {
+             regno = REGNO (XVECEXP (src, 0, 0));
+             if (!spill_offset_emitted)
+               {
+                 fprintf (asm_out_file, "\t.spill %d\n", 
+/*                        (frame_size + 16 - spill_offset ) / 4); */
+                          (-(spill_offset - 8) + 16) / 4);
+                 spill_offset_emitted = 1;
+               }
+           }
+         else
+           regno = REGNO (src);
+
+          if (GR_REGNO_P (regno))
+           {
+             if (regno >= GR_REG (4) && regno <= GR_REG (7))
+               fprintf (asm_out_file, "\t.save.g 0x%x\n", 
+                        1 << (regno - GR_REG (4)));
+             else if (tmp_reg != NULL_RTX && regno == REGNO (tmp_reg))
+               {
+                 /* We saved a special reg to a temp reg, and now we're 
+                    dumping it to memory.  */
+                 tmp_reg = NULL_RTX;
+                 /* register 9 is ar.unat.  */
+                 if (tmp_saved == 9)
+                   fprintf (asm_out_file, "\t.savesp ar.unat, %d\n", 
+                            (sp_offset - 8) / 4);
+                 else if (tmp_saved == 5)
+                   fprintf (asm_out_file, "\t.savesp pr, %d\n",
+                            (sp_offset - 8) / 4);
+                 else if (tmp_saved >= BR_REG (1) && tmp_saved <= BR_REG (5))
+                   {
+                     /* BR regs are saved this way too.  */
+                     fprintf (asm_out_file, "\t.save.b 0x%x\n", 
+                              1 << (tmp_saved - BR_REG (1)));
+                   }
+               }
+             else 
+               return 0;
+           }
+         if (FR_REGNO_P (regno))
+           {
+             if (regno >= FR_REG (2) && regno <= FR_REG (5))
+               fprintf (asm_out_file, "\t.save.f 0x%x\n", 
+                        1 << (regno - FR_REG (2)));
+             else
+               if (regno >= FR_REG (16) && regno <= FR_REG (31))
+                 fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n", 
+                          1 << (regno - FR_REG (12)));
+               else 
+                 return 0;
+           }
+         return 1;
+       }
+    }
+  return 0;
+}
+
+
+/* This function looks at a single insn and emits any directives
+   required to unwind this insn.  */
+void
+process_for_unwind_directive (asm_out_file, insn)
+     FILE *asm_out_file;
+     rtx insn;
+{
+  if ((flag_unwind_tables 
+       || (flag_exceptions && !exceptions_via_longjmp))
+      && RTX_FRAME_RELATED_P (insn))
+    {
+      rtx code, pat;
+      pat = PATTERN (insn);
+
+      switch (GET_CODE (pat))
+        {
+         case SET:
+           {
+             process_set (asm_out_file, pat);
+             break;
+           }
+         case PARALLEL:
+           {
+             int par_index;
+             int limit = XVECLEN (pat, 0);
+             for (par_index = 0; par_index < limit; par_index++)
+               {
+                 rtx x = XVECEXP (pat, 0, par_index);
+                 if (GET_CODE (x) == SET)
+                   process_set (asm_out_file, x);
+               }
+             break;
+           }
+       }
+    }
+}
 
 #define def_builtin(name, type, code) \
   builtin_function ((name), (type), (code), BUILT_IN_MD, NULL_PTR)
index dca777477b15b034e8dc422551cc3fd3d3002d44..be921f958b45a72ff10f9a7198c2a4b848028114 100644 (file)
@@ -2115,6 +2115,71 @@ do {                                                                     \
   fprintf (FILE, "\n");                                                        \
 } while (0)
 
+/* This is how to output an assembler line defining a `char' constant
+   to an xdata segment.  */
+
+#define ASM_OUTPUT_XDATA_CHAR(FILE, SECTION, VALUE)                    \
+do {                                                                   \
+  fprintf (FILE, "\t.xdata1\t\"%s\", ", SECTION);                      \
+  output_addr_const (FILE, (VALUE));                                   \
+  fprintf (FILE, "\n");                                                        \
+} while (0)
+
+/* This is how to output an assembler line defining a `short' constant
+   to an xdata segment.  */
+
+#define ASM_OUTPUT_XDATA_SHORT(FILE, SECTION, VALUE)                   \
+do {                                                                   \
+  fprintf (FILE, "\t.xdata2\t\"%s\", ", SECTION);                      \
+  output_addr_const (FILE, (VALUE));                                   \
+  fprintf (FILE, "\n");                                                        \
+} while (0)
+
+/* This is how to output an assembler line defining an `int' constant
+   to an xdata segment.  We also handle symbol output here.  */
+
+/* ??? For ILP32, also need to handle function addresses here.  */
+
+#define ASM_OUTPUT_XDATA_INT(FILE, SECTION, VALUE)                     \
+do {                                                                   \
+  fprintf (FILE, "\t.xdata4\t\"%s\", ", SECTION);                      \
+  output_addr_const (FILE, (VALUE));                                   \
+  fprintf (FILE, "\n");                                                        \
+} while (0)
+
+/* This is how to output an assembler line defining a `long' constant
+   to an xdata segment.  We also handle symbol output here.  */
+
+#define ASM_OUTPUT_XDATA_DOUBLE_INT(FILE, SECTION, VALUE)              \
+do {                                                                   \
+  fprintf (FILE, "\t.xdata8\t\"%s\", ", SECTION);                      \
+  if (GET_CODE (VALUE) == SYMBOL_REF)                                  \
+    {                                                                  \
+      if (SYMBOL_REF_FLAG (VALUE))                                     \
+       fprintf (FILE, "@fptr(");                                       \
+      else                                                             \
+       fprintf (FILE, "@segrel(");                                     \
+    }                                                                  \
+  output_addr_const (FILE, (VALUE));                                   \
+  if (GET_CODE (VALUE) == SYMBOL_REF)                                  \
+    fprintf (FILE, ")");                                               \
+  fprintf (FILE, "\n");                                                        \
+} while (0)
+
+
+/* Output EH data to the unwind segment. */
+#define ASM_OUTPUT_EH_CHAR(FILE, VALUE)                                        \
+               ASM_OUTPUT_XDATA_CHAR(FILE, ".IA_64.unwind_info", VALUE)
+
+#define ASM_OUTPUT_EH_SHORT(FILE, VALUE)                               \
+               ASM_OUTPUT_XDATA_SHORT(FILE, ".IA_64.unwind_info", VALUE)
+
+#define ASM_OUTPUT_EH_INT(FILE, VALUE)                                 \
+               ASM_OUTPUT_XDATA_INT(FILE, ".IA_64.unwind_info", VALUE)
+
+#define ASM_OUTPUT_EH_DOUBLE_INT(FILE, VALUE)                          \
+               ASM_OUTPUT_XDATA_DOUBLE_INT(FILE, ".IA_64.unwind_info", VALUE)
+
 /* A C statement to output to the stdio stream STREAM an assembler instruction
    to assemble a single byte containing the number VALUE.  */
 
@@ -2453,7 +2518,7 @@ do {                                                                      \
 
    You should define this symbol if your target supports DWARF 2 frame unwind
    information and the default definition does not work.  */
-/* #define EH_FRAME_SECTION_ASM_OP */
+#define EH_FRAME_SECTION_ASM_OP ".section\t.IA_64.unwind,\"aw\""
 
 /* A C expression that is nonzero if the normal exception table output should
    be omitted.
@@ -2739,6 +2804,21 @@ do {                                                                     \
 
 #define ISSUE_RATE 3
 
+#define IA64_UNWIND_INFO       1
+#define HANDLER_SECTION fprintf (asm_out_file, "\t.personality\t__ia64_personality_v1\n\t.handlerdata\n");
+#define IA64_UNWIND_EMIT(f,i)  process_for_unwind_directive (f,i)
+
+/* This function contains machine specific function data.  */
+struct machine_function
+{
+  /* The new stack pointer when unwinding from EH.  */
+  struct rtx_def* ia64_eh_epilogue_sp;
+
+  /* The new bsp value when unwinding from EH. */
+  struct rtx_def* ia64_eh_epilogue_bsp;
+};
+
+
 enum ia64_builtins
 {
   IA64_BUILTIN_SYNCHRONIZE,
index d3df3cb7cb1f22f2577ef5ee1f9453becae069d8..e9ef493ecdd1f563bfeff7ea58d5382b2be5b5df 100644 (file)
   "mov ar.unat = %0"
   [(set_attr "type" "M")])
 
+(define_insn "bsp_value"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI [(const_int 0)] 20))]
+  ""
+  "mov %0 = ar.bsp"
+  [(set_attr "type" "I")])
+
+(define_insn "set_bsp"
+  [(unspec_volatile [(const_int 0)] 5)
+   (use (match_operand:DI 0 "register_operand" "r"))]
+  ""
+  "flushrs\;                   \
+   mov r19=ar.rsc\;            \
+   ;;\;                                \
+   and r19=0x1c,r19\;          \
+   ;;\;                                \
+   mov ar.rsc=r19\;            \
+   ;;\;                                \
+   mov ar.bspstore=%0\;                \
+   ;;\;                                \
+   or r19=0x3,r19\;            \
+   ;;\;                                \
+   loadrs\;                    \
+   invala\;                    \
+   ;;\;                                \
+   mov ar.rsc=r19\;"
+  [(set_attr "type" "I")])
 \f
 ;; ::::::::::::::::::::
 ;; ::
   DONE;
 }")
 
+(define_expand "eh_epilogue"
+  [(use (match_operand:DI 0 "register_operand" "r"))
+   (use (match_operand:DI 1 "register_operand" "r"))
+   (use (match_operand:DI 2 "register_operand" "r"))]
+  ""
+  "
+{
+  rtx bsp = gen_rtx_REG (Pmode, 10);
+  rtx sp = gen_rtx_REG (Pmode, 9);
+
+  if (GET_CODE (operands[0]) != REG || REGNO (operands[0]) != 10)
+    {
+      emit_move_insn (bsp, operands[0]);
+      operands[0] = bsp;
+    }
+  if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 9)
+    {
+      emit_move_insn (sp, operands[2]);
+      operands[2] = sp;
+    }
+  emit_insn (gen_rtx_USE (VOIDmode, sp));
+  emit_insn (gen_rtx_USE (VOIDmode, bsp));
+
+  cfun->machine->ia64_eh_epilogue_sp = sp;
+  cfun->machine->ia64_eh_epilogue_bsp = bsp;
+
+}")
+
 ;; This flushes at least 64 bytes starting from the address pointed
 ;; to by operand[0].