From 0c96007e77cab88c49c2ec4101716d15e0883971 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Tue, 25 Apr 2000 23:16:20 +0000 Subject: [PATCH] Add partial support for IA-64 unwind sections. * 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 Co-Authored-By: Jim Wilson From-SVN: r33424 --- gcc/ChangeLog | 30 +++ gcc/config/ia64/crtbegin.asm | 128 ++++++++++++- gcc/config/ia64/crtend.asm | 4 + gcc/config/ia64/ia64.c | 421 +++++++++++++++++++++++++++++++++++++------ gcc/config/ia64/ia64.h | 82 ++++++++- gcc/config/ia64/ia64.md | 55 ++++++ 6 files changed, 652 insertions(+), 68 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 89d3dd4..9ec1116 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +Tue Apr 25 16:16:04 2000 Andrew MacLeod + Jim Wilson + Andrew Haley + + * 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 * fixinc/Makefile.in: make the removal of old programs more diff --git a/gcc/config/ia64/crtbegin.asm b/gcc/config/ia64/crtbegin.asm index b77ad98..d44df5b 100644 --- a/gcc/config/ia64/crtbegin.asm +++ b/gcc/config/ia64/crtbegin.asm @@ -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 ;; @@ -139,9 +171,36 @@ __do_global_dtors_aux: 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# diff --git a/gcc/config/ia64/crtend.asm b/gcc/config/ia64/crtend.asm index 3da0f96..208c469 100644 --- a/gcc/config/ia64/crtend.asm +++ b/gcc/config/ia64/crtend.asm @@ -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. * diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 362c858..dbc89d7 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -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 (); } @@ -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) } } } + +/* 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) diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index dca7774..be921f9 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -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, diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index d3df3cb..e9ef493e 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -3083,6 +3083,33 @@ "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")]) ;; :::::::::::::::::::: ;; :: @@ -3166,6 +3193,34 @@ 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]. -- 2.7.4