diff options
author | danglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-03-19 04:41:48 +0000 |
---|---|---|
committer | danglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-03-19 04:41:48 +0000 |
commit | e9ec370e36b7c4ca140202deab4aff94817683c5 (patch) | |
tree | 8cab564fd46594fddefc2c1e4e53ef844b33310a /gcc/config/pa | |
parent | 3a32429b826bfb2575ba0b7eb1d652c5a820632a (diff) | |
download | gcc-e9ec370e36b7c4ca140202deab4aff94817683c5.tar.gz |
PR 10062
* config/pa/pa-hpux.h (TARGET_HPUX_UNWIND_LIBRARY): Redefine.
* pa-protos.h (output_lbranch): New prototype.
* pa.c (compute_frame_size): Change size of the frame marker on the
64-bit ports to 48 bytes.
(pa_output_function_prologue): Document why SAVE_SP is set.
(hppa_expand_prologue): Save previous stack pointer into frame marker
on targets which use the hpux unwind library.
(output_cbranch): Use output_lbranch.
(output_lbranch): New function to output long unconditional branches.
* pa.h (TARGET_HPUX_UNWIND_LIBRARY): Define.
(STACK_POINTER_OFFSET): Update offset for 48-byte frame marker on
64-bit ports.
* pa.md (jump): Use output_lbranch.
(allocate_stack): New expander for dynamic stack allocation.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@64570 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/pa')
-rw-r--r-- | gcc/config/pa/pa-hpux.h | 5 | ||||
-rw-r--r-- | gcc/config/pa/pa-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/pa/pa.c | 277 | ||||
-rw-r--r-- | gcc/config/pa/pa.h | 17 | ||||
-rw-r--r-- | gcc/config/pa/pa.md | 93 |
5 files changed, 253 insertions, 140 deletions
diff --git a/gcc/config/pa/pa-hpux.h b/gcc/config/pa/pa-hpux.h index a4ed77f983e..d6e15164013 100644 --- a/gcc/config/pa/pa-hpux.h +++ b/gcc/config/pa/pa-hpux.h @@ -100,3 +100,8 @@ Boston, MA 02111-1307, USA. */ /* hpux11 and earlier don't have fputc_unlocked, so we must inhibit the transformation of fputs_unlocked and fprintf_unlocked to fputc_unlocked. */ #define DONT_HAVE_FPUTC_UNLOCKED + +/* We want the entry value of SP saved in the frame marker for + compatibility with the HP-UX unwind library. */ +#undef TARGET_HPUX_UNWIND_LIBRARY +#define TARGET_HPUX_UNWIND_LIBRARY 1 diff --git a/gcc/config/pa/pa-protos.h b/gcc/config/pa/pa-protos.h index 248e1a7d05e..16c9fbf079a 100644 --- a/gcc/config/pa/pa-protos.h +++ b/gcc/config/pa/pa-protos.h @@ -44,6 +44,7 @@ extern const char *output_move_double PARAMS ((rtx *)); extern const char *output_fp_move_double PARAMS ((rtx *)); extern const char *output_block_move PARAMS ((rtx *, int)); extern const char *output_cbranch PARAMS ((rtx *, int, int, int, rtx)); +extern const char *output_lbranch PARAMS ((rtx, rtx)); extern const char *output_bb PARAMS ((rtx *, int, int, int, rtx, int)); extern const char *output_bvb PARAMS ((rtx *, int, int, int, rtx, int)); extern const char *output_dbra PARAMS ((rtx *, rtx, int)); diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 921e606edb7..83205ba2568 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -3270,10 +3270,10 @@ compute_frame_size (size, fregs_live) size += current_function_outgoing_args_size; /* Allocate space for the fixed frame marker. This space must be - allocated for any function that makes calls or otherwise allocates + allocated for any function that makes calls or allocates stack space. */ if (!current_function_is_leaf || size) - size += TARGET_64BIT ? 16 : 32; + size += TARGET_64BIT ? 48 : 32; /* Finally, round to the preferred stack boundary. */ return ((size + PREFERRED_STACK_BOUNDARY / 8 - 1) @@ -3317,6 +3317,15 @@ pa_output_function_prologue (file, size) else fputs (",NO_CALLS", file); + /* The SAVE_SP flag is used to indicate that register %r3 is stored + at the beginning of the frame and that it is used as the frame + pointer for the frame. We do this because our current frame + layout doesn't conform to that specified in the the HP runtime + documentation and we need a way to indicate to programs such as + GDB where %r3 is saved. The SAVE_SP flag was chosen because it + isn't used by HP compilers but is supported by the assembler. + However, SAVE_SP is supposed to indicate that the previous stack + pointer has been saved in the frame marker. */ if (frame_pointer_needed) fputs (",SAVE_SP", file); @@ -3416,11 +3425,32 @@ hppa_expand_prologue () adjust2, 1); } - /* Prevent register spills from being scheduled before the - stack pointer is raised. Necessary as we will be storing - registers using the frame pointer as a base register, and - we happen to set fp before raising sp. */ - emit_insn (gen_blockage ()); + /* We set SAVE_SP in frames that need a frame pointer. Thus, + we need to store the previous stack pointer (frame pointer) + into the frame marker on targets that use the HP unwind + library. This allows the HP unwind library to be used to + unwind GCC frames. However, we are not fully compatible + with the HP library because our frame layout differs from + that specified in the HP runtime specification. + + We don't want a frame note on this instruction as the frame + marker moves during dynamic stack allocation. + + This instruction also serves as a blockage to prevent + register spills from being scheduled before the stack + pointer is raised. This is necessary as we store + registers using the frame pointer as a base register, + and the frame pointer is set before sp is raised. */ + if (TARGET_HPUX_UNWIND_LIBRARY) + { + rtx addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx, + GEN_INT (TARGET_64BIT ? -8 : -4)); + + emit_move_insn (gen_rtx_MEM (word_mode, addr), + frame_pointer_rtx); + } + else + emit_insn (gen_blockage ()); } /* no frame pointer needed. */ else @@ -5517,6 +5547,7 @@ output_cbranch (operands, nullify, length, negated, insn) { static char buf[100]; int useskip = 0; + rtx xoperands[5]; /* A conditional branch to the following instruction (eg the delay slot) is asking for a disaster. This can happen when not optimizing. @@ -5622,98 +5653,182 @@ output_cbranch (operands, nullify, length, negated, insn) break; case 20: - /* Very long branch. Right now we only handle these when not - optimizing. See "jump" pattern in pa.md for details. */ - if (optimize) - abort (); + case 28: + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = operands[2]; + xoperands[3] = operands[3]; + + /* The reversed conditional branch must branch over one additional + instruction if the delay slot is filled. If the delay slot + is empty, the instruction after the reversed condition branch + must be nullified. */ + nullify = dbr_sequence_length () == 0; + xoperands[4] = nullify ? GEN_INT (length) : GEN_INT (length + 4); /* Create a reversed conditional branch which branches around the following insns. */ - if (negated) - strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+20|cmp%I2b,%S3,n %2,%r1,.+20}"); + if (GET_MODE (operands[1]) != DImode) + { + if (nullify) + { + if (negated) + strcpy (buf, + "{com%I2b,%S3,n %2,%r1,.+%4|cmp%I2b,%S3,n %2,%r1,.+%4}"); + else + strcpy (buf, + "{com%I2b,%B3,n %2,%r1,.+%4|cmp%I2b,%B3,n %2,%r1,.+%4}"); + } + else + { + if (negated) + strcpy (buf, + "{com%I2b,%S3 %2,%r1,.+%4|cmp%I2b,%S3 %2,%r1,.+%4}"); + else + strcpy (buf, + "{com%I2b,%B3 %2,%r1,.+%4|cmp%I2b,%B3 %2,%r1,.+%4}"); + } + } else - strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+20|cmp%I2b,%B3,n %2,%r1,.+20}"); - if (GET_MODE (operands[1]) == DImode) { - if (negated) - strcpy (buf, - "{com%I2b,*%S3,n %2,%r1,.+20|cmp%I2b,*%S3,n %2,%r1,.+20}"); + if (nullify) + { + if (negated) + strcpy (buf, + "{com%I2b,*%S3,n %2,%r1,.+%4|cmp%I2b,*%S3,n %2,%r1,.+%4}"); + else + strcpy (buf, + "{com%I2b,*%B3,n %2,%r1,.+%4|cmp%I2b,*%B3,n %2,%r1,.+%4}"); + } else - strcpy (buf, - "{com%I2b,*%B3,n %2,%r1,.+20|cmp%I2b,*%B3,n %2,%r1,.+20}"); + { + if (negated) + strcpy (buf, + "{com%I2b,*%S3 %2,%r1,.+%4|cmp%I2b,*%S3 %2,%r1,.+%4}"); + else + strcpy (buf, + "{com%I2b,*%B3 %2,%r1,.+%4|cmp%I2b,*%B3 %2,%r1,.+%4}"); + } } - output_asm_insn (buf, operands); - /* Output an insn to save %r1. */ - output_asm_insn ("stw %%r1,-16(%%r30)", operands); + output_asm_insn (buf, xoperands); + return output_lbranch (operands[0], insn); - /* Now output a very long branch to the original target. */ - output_asm_insn ("ldil L'%l0,%%r1\n\tbe R'%l0(%%sr4,%%r1)", operands); + default: + abort (); + } + return buf; +} - /* Now restore the value of %r1 in the delay slot. We're not - optimizing so we know nothing else can be in the delay slot. */ - return "ldw -16(%%r30),%%r1"; +/* This routine handles long unconditional branches that exceed the + maximum range of a simple branch instruction. */ - case 28: - /* Very long branch when generating PIC code. Right now we only - handle these when not optimizing. See "jump" pattern in pa.md - for details. */ - if (optimize) - abort (); +const char * +output_lbranch (dest, insn) + rtx dest, insn; +{ + rtx xoperands[2]; + + xoperands[0] = dest; - /* Create a reversed conditional branch which branches around - the following insns. */ - if (negated) - strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+28|cmp%I2b,%S3,n %2,%r1,.+28}"); - else - strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+28|cmp%I2b,%B3,n %2,%r1,.+28}"); - if (GET_MODE (operands[1]) == DImode) - { - if (negated) - strcpy (buf, "{com%I2b,*%S3,n %2,%r1,.+28|cmp%I2b,*%S3,n %2,%r1,.+28}"); - else - strcpy (buf, "{com%I2b,*%B3,n %2,%r1,.+28|cmp%I2b,*%B3,n %2,%r1,.+28}"); - } - output_asm_insn (buf, operands); + /* First, free up the delay slot. */ + if (dbr_sequence_length () != 0) + { + /* We can't handle a jump in the delay slot. */ + if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) + abort (); - /* Output an insn to save %r1. */ - output_asm_insn ("stw %%r1,-16(%%r30)", operands); + final_scan_insn (NEXT_INSN (insn), asm_out_file, + optimize, 0, 0); + + /* Now delete the delay insn. */ + PUT_CODE (NEXT_INSN (insn), NOTE); + NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0; + } + + /* Output an insn to save %r1. The runtime documentation doesn't + specify whether the "Clean Up" slot in the callers frame can + be clobbered by the callee. It isn't copied by HP's builtin + alloca, so this suggests that it can be clobbered if necessary. + The "Static Link" location is copied by HP builtin alloca, so + we avoid using it. Using the cleanup slot might be a problem + if we have to interoperate with languages that pass cleanup + information. However, it should be possible to handle these + situations with GCC's asm feature. + + The "Current RP" slot is reserved for the called procedure, so + we try to use it when we don't have a frame of our own. It's + rather unlikely that we won't have a frame when we need to emit + a very long branch. + + Really the way to go long term is a register scavenger; goto + the target of the jump and find a register which we can use + as a scratch to hold the value in %r1. Then, we wouldn't have + to free up the delay slot or clobber a slot that may be needed + for other purposes. */ + if (TARGET_64BIT) + { + if (actual_fsize == 0 && !regs_ever_live[2]) + /* Use the return pointer slot in the frame marker. */ + output_asm_insn ("std %%r1,-16(%%r30)", xoperands); + else + /* Use the slot at -40 in the frame marker since HP builtin + alloca doesn't copy it. */ + output_asm_insn ("std %%r1,-40(%%r30)", xoperands); + } + else + { + if (actual_fsize == 0 && !regs_ever_live[2]) + /* Use the return pointer slot in the frame marker. */ + output_asm_insn ("stw %%r1,-20(%%r30)", xoperands); + else + /* Use the "Clean Up" slot in the frame marker. In GCC, + the only other use of this location is for copying a + floating point double argument from a floating-point + register to two general registers. The copy is done + as an "atomic" operation when outputing a call, so it + won't interfere with our using the location here. */ + output_asm_insn ("stw %%r1,-12(%%r30)", xoperands); + } - /* Now output a very long PIC branch to the original target. */ + if (flag_pic) + { + output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); + if (TARGET_SOM || !TARGET_GAS) { - rtx xoperands[5]; - - xoperands[0] = operands[0]; - xoperands[1] = operands[1]; - xoperands[2] = operands[2]; - xoperands[3] = operands[3]; - - output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); - if (TARGET_SOM || !TARGET_GAS) - { - xoperands[4] = gen_label_rtx (); - output_asm_insn ("addil L'%l0-%l4,%%r1", xoperands); - (*targetm.asm_out.internal_label) (asm_out_file, "L", - CODE_LABEL_NUMBER (xoperands[4])); - output_asm_insn ("ldo R'%l0-%l4(%%r1),%%r1", xoperands); - } - else - { - output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands); - output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1", - xoperands); - } - output_asm_insn ("bv %%r0(%%r1)", xoperands); + xoperands[1] = gen_label_rtx (); + output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands); + (*targetm.asm_out.internal_label) (asm_out_file, "L", + CODE_LABEL_NUMBER (xoperands[1])); + output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands); } + else + { + output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands); + output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands); + } + output_asm_insn ("bv %%r0(%%r1)", xoperands); + } + else + /* Now output a very long branch to the original target. */ + output_asm_insn ("ldil L'%l0,%%r1\n\tbe R'%l0(%%sr4,%%r1)", xoperands); - /* Now restore the value of %r1 in the delay slot. We're not - optimizing so we know nothing else can be in the delay slot. */ - return "ldw -16(%%r30),%%r1"; - - default: - abort (); + /* Now restore the value of %r1 in the delay slot. */ + if (TARGET_64BIT) + { + if (actual_fsize == 0 && !regs_ever_live[2]) + return "ldd -16(%%r30),%%r1"; + else + return "ldd -40(%%r30),%%r1"; + } + else + { + if (actual_fsize == 0 && !regs_ever_live[2]) + return "ldw -20(%%r30),%%r1"; + else + return "ldw -12(%%r30),%%r1"; } - return buf; } /* This routine handles all the branch-on-bit conditional branch sequences we diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index 86590583139..177cae33ddc 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -211,6 +211,15 @@ extern int target_flags; definition symbols is buggy prior to HP-UX 11.X. */ #define TARGET_SOM_SDEF 0 +/* Define to a C expression evaluating to true to save the entry value + of SP in the current frame marker. This is normally unnecessary. + However, the HP-UX unwind library looks at the SAVE_SP callinfo flag. + HP compilers don't use this flag but it is supported by the assembler. + We set this flag to indicate that register %r3 has been saved at the + start of the frame. Thus, when the HP unwind library is used, we + need to generate additional code to save SP into the frame marker. */ +#define TARGET_HPUX_UNWIND_LIBRARY 0 + /* Macro to define tables used to set the flags. This is a list in braces of target switches with each switch being { "NAME", VALUE, "HELP_STRING" }. VALUE is the bits to set, @@ -714,9 +723,13 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void)); /* The weird HPPA calling conventions require a minimum of 48 bytes on the stack: 16 bytes for register saves, and 32 bytes for magic. This is the difference between the logical top of stack and the - actual sp. */ + actual sp. + + On the 64-bit port, the HP C compiler allocates a 48-byte frame + marker, although the runtime documentation only describes a 16 + byte marker. For compatibility, we allocate 48 bytes. */ #define STACK_POINTER_OFFSET \ - (TARGET_64BIT ? -(current_function_outgoing_args_size + 16): -32) + (TARGET_64BIT ? -(current_function_outgoing_args_size + 48): -32) #define STACK_DYNAMIC_OFFSET(FNDECL) \ (TARGET_64BIT \ diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 2673739849f..0f50c8ff71d 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -5721,8 +5721,6 @@ "" "* { - extern int optimize; - if (GET_MODE (insn) == SImode) return \"b %l0%#\"; @@ -5731,61 +5729,7 @@ && get_attr_length (insn) != 16) return \"b%* %l0\"; - /* An unconditional branch which can not reach its target. - - We need to be able to use %r1 as a scratch register; however, - we can never be sure whether or not it's got a live value in - it. Therefore, we must restore its original value after the - jump. - - To make matters worse, we don't have a stack slot which we - can always clobber. sp-12/sp-16 shouldn't ever have a live - value during a non-optimizing compilation, so we use those - slots for now. We don't support very long branches when - optimizing -- they should be quite rare when optimizing. - - Really the way to go long term is a register scavenger; goto - the target of the jump and find a register which we can use - as a scratch to hold the value in %r1. */ - - /* We don't know how to register scavenge yet. */ - if (optimize) - abort (); - - /* First store %r1 into the stack. */ - output_asm_insn (\"stw %%r1,-16(%%r30)\", operands); - - /* Now load the target address into %r1 and do an indirect jump - to the value specified in %r1. Be careful to generate PIC - code as needed. */ - if (flag_pic) - { - rtx xoperands[2]; - xoperands[0] = operands[0]; - if (TARGET_SOM || ! TARGET_GAS) - { - xoperands[1] = gen_label_rtx (); - - output_asm_insn (\"{bl|b,l} .+8,%%r1\\n\\taddil L'%l0-%l1,%%r1\", - xoperands); - (*targetm.asm_out.internal_label) (asm_out_file, \"L\", - CODE_LABEL_NUMBER (xoperands[1])); - output_asm_insn (\"ldo R'%l0-%l1(%%r1),%%r1\", xoperands); - } - else - { - output_asm_insn (\"{bl|b,l} .+8,%%r1\", xoperands); - output_asm_insn (\"addil L'%l0-$PIC_pcrel$0+4,%%r1\", xoperands); - output_asm_insn (\"ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1\", xoperands); - } - output_asm_insn (\"bv %%r0(%%r1)\", xoperands); - } - else - output_asm_insn (\"ldil L'%l0,%%r1\\n\\tbe R'%l0(%%sr4,%%r1)\", operands);; - - /* And restore the value of %r1 in the delay slot. We're not optimizing, - so we know nothing else can be in the delay slot. */ - return \"ldw -16(%%r30),%%r1\"; + return output_lbranch (operands[0], insn); }" [(set_attr "type" "uncond_branch") (set_attr "pa_combine_type" "uncond_branch") @@ -8053,3 +7997,38 @@ emit_insn (gen_blockage ()); DONE; }") + +;; Allocate new stack space and update the saved stack pointer in the +;; frame marker. The HP C compilers also copy additional words in the +;; frame marker. The 64-bit compiler copies words at -48, -32 and -24. +;; The 32-bit compiler copies the word at -16 (Static Link). We +;; currently don't copy these values. +;; +;; Since the copy of the frame marker can't be done atomically, I +;; suspect that using it for unwind purposes may be somewhat unreliable. +;; The HP compilers appear to raise the stack and copy the frame +;; marker in a strict instruction sequence. This suggests that the +;; unwind library may check for an alloca sequence when ALLOCA_FRAME +;; is set in the callinfo data. We currently don't set ALLOCA_FRAME +;; as GAS doesn't support it, or try to keep the instructions emitted +;; here in strict sequence. +(define_expand "allocate_stack" + [(match_operand 0 "" "") + (match_operand 1 "" "")] + "" + " +{ + /* Since the stack grows upward, we need to store virtual_stack_dynamic_rtx + in operand 0 before adjusting the stack. */ + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + anti_adjust_stack (operands[1]); + if (TARGET_HPUX_UNWIND_LIBRARY) + { + rtx dst = gen_rtx_MEM (word_mode, + gen_rtx_PLUS (word_mode, stack_pointer_rtx, + GEN_INT (TARGET_64BIT ? -8 : -4))); + + emit_move_insn (dst, frame_pointer_rtx); + } + DONE; +}") |