aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1993-07-09 14:22:50 -0600
committerJeff Law <law@gcc.gnu.org>1993-07-09 14:22:50 -0600
commitb1a275e1e03d6fd70bac89c750b5158bb369e71d (patch)
tree9fd78a1db32c44c54d28e820a414469bad082511 /gcc
parent98b2d887833f25794d0febba4ea1fcf65a9490c2 (diff)
downloadgcc-b1a275e1e03d6fd70bac89c750b5158bb369e71d.zip
gcc-b1a275e1e03d6fd70bac89c750b5158bb369e71d.tar.gz
gcc-b1a275e1e03d6fd70bac89c750b5158bb369e71d.tar.bz2
pa.c (pa_adjust_insn_length): dbra and movb insns which have their output in a FP register do not need adjustment.
* pa.c (pa_adjust_insn_length): dbra and movb insns which have their output in a FP register do not need adjustment. (output_cbranch, output_bb): Handle conditional jump to the following instruction. (output_dbra): New function extracted from dbra pattern. (output_movb): New function. (eq_neq_comparison_operator): New function. (movb_comparison_operator): New function. From-SVN: r4888
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/pa/pa.c234
1 files changed, 231 insertions, 3 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 478ca9e..fc61ca5 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -2543,10 +2543,12 @@ pa_adjust_insn_length (insn, length)
&& ! forward_branch_p (insn))
return 1;
/* Adjust dbra insn with short backwards conditional branch with
- unfilled delay slot -- only for case where counter is in a register. */
+ unfilled delay slot -- only for case where counter is in a
+ general register register. */
else if (GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 1)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == REG
+ && ! FP_REG_P (XEXP (XVECEXP (pat, 0, 1), 0))
&& length == 1
&& ! forward_branch_p (insn))
return 1;
@@ -3250,10 +3252,18 @@ output_cbranch (operands, nullify, length, negated, insn)
rtx *operands;
int nullify, length, negated;
rtx insn;
-{
+{
static char buf[100];
int useskip = 0;
+ /* A conditional branch to the following instruction (eg the delay slot) is
+ asking for a disaster. This can happen when not optimizing.
+
+ In such cases it is safe to emit nothing. */
+
+ if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
+ return "";
+
/* If this is a long branch with its delay slot unfilled, set `nullify'
as it can nullify the delay slot and save a nop. */
if (length == 2 && dbr_sequence_length () == 0)
@@ -3343,10 +3353,18 @@ output_bb (operands, nullify, length, negated, insn, which)
int nullify, length, negated;
rtx insn;
int which;
-{
+{
static char buf[100];
int useskip = 0;
+ /* A conditional branch to the following instruction (eg the delay slot) is
+ asking for a disaster. I do not think this can happen as this pattern
+ is only used when optimizing; jump optimization should eliminate the
+ jump. But be prepared just in case. */
+
+ if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
+ return "";
+
/* If this is a long branch with its delay slot unfilled, set `nullify'
as it can nullify the delay slot and save a nop. */
if (length == 2 && dbr_sequence_length () == 0)
@@ -3441,6 +3459,197 @@ output_bb (operands, nullify, length, negated, insn, which)
return buf;
}
+/* Return the output template for emitting a dbra type insn.
+
+ Note it may perform some output operations on its own before
+ returning the final output string. */
+char *
+output_dbra (operands, insn, which_alternative)
+ rtx *operands;
+ rtx insn;
+ int which_alternative;
+{
+
+ /* A conditional branch to the following instruction (eg the delay slot) is
+ asking for a disaster. Be prepared! */
+
+ if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
+ {
+ if (which_alternative == 0)
+ return "ldo %1(%0),%0";
+ else if (which_alternative == 1)
+ {
+ output_asm_insn ("fstws %0,-16(0,%%r30)",operands);
+ output_asm_insn ("ldw -16(0,%%r30),%4",operands);
+ output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(0,%%r30)", operands);
+ return "fldws -16(0,%%r30),%0";
+ }
+ else
+ {
+ output_asm_insn ("ldw %0,%4", operands);
+ return "ldo %1(%4),%4\n\tstw %4,%0";
+ }
+ }
+
+ if (which_alternative == 0)
+ {
+ int nullify = INSN_ANNULLED_BRANCH_P (insn);
+ int length = get_attr_length (insn);
+
+ /* If this is a long branch with its delay slot unfilled, set `nullify'
+ as it can nullify the delay slot and save a nop. */
+ if (length == 2 && dbr_sequence_length () == 0)
+ nullify = 1;
+
+ /* If this is a short forward conditional branch which did not get
+ its delay slot filled, the delay slot can still be nullified. */
+ if (! nullify && length == 1 && dbr_sequence_length () == 0)
+ nullify = forward_branch_p (insn);
+
+ /* Handle short versions first. */
+ if (length == 1 && nullify)
+ return "addib,%C2,n %1,%0,%3";
+ else if (length == 1 && ! nullify)
+ return "addib,%C2 %1,%0,%3";
+ else if (length == 2)
+ {
+ /* Handle weird backwards branch with a fulled delay slot
+ which is nullified. */
+ if (dbr_sequence_length () != 0
+ && ! forward_branch_p (insn)
+ && nullify)
+ return "addib,%N2,n %1,%0,.+12\n\tbl %3,0";
+
+ /* Handle normal cases. */
+ if (nullify)
+ return "addi,%N2 %1,%0,%0\n\tbl,n %3,0";
+ else
+ return "addi,%N2 %1,%0,%0\n\tbl %3,0";
+ }
+ else
+ abort();
+ }
+ /* Deal with gross reload from FP register case. */
+ else if (which_alternative == 1)
+ {
+ /* Move loop counter from FP register to MEM then into a GR,
+ increment the GR, store the GR into MEM, and finally reload
+ the FP register from MEM from within the branch's delay slot. */
+ output_asm_insn ("fstws %0,-16(0,%%r30)\n\tldw -16(0,%%r30),%4",operands);
+ output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(0,%%r30)", operands);
+ if (get_attr_length (insn) == 6)
+ return "comb,%S2 0,%4,%3\n\tfldws -16(0,%%r30),%0";
+ else
+ return "comclr,%B2 0,%4,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
+ }
+ /* Deal with gross reload from memory case. */
+ else
+ {
+ /* Reload loop counter from memory, the store back to memory
+ happens in the branch's delay slot. */
+ output_asm_insn ("ldw %0,%4", operands);
+ if (get_attr_length (insn) == 3)
+ return "addib,%C2 %1,%4,%3\n\tstw %4,%0";
+ else
+ return "addi,%N2 %1,%4,%0\n\tbl %3,0\n\tstw %4,%0";
+ }
+}
+
+/* Return the output template for emitting a dbra type insn.
+
+ Note it may perform some output operations on its own before
+ returning the final output string. */
+char *
+output_movb (operands, insn, which_alternative, reverse_comparison)
+ rtx *operands;
+ rtx insn;
+ int which_alternative;
+ int reverse_comparison;
+{
+
+ /* A conditional branch to the following instruction (eg the delay slot) is
+ asking for a disaster. Be prepared! */
+
+ if (JUMP_LABEL (insn) == next_nonnote_insn (insn))
+ {
+ if (which_alternative == 0)
+ return "copy %1,%0";
+ else if (which_alternative == 1)
+ {
+ output_asm_insn ("fstws %1,-16(0,%%r30)",operands);
+ return "fldws -16(0,%%r30),%0";
+ }
+ else
+ return "stw %1,%0";
+ }
+
+ /* Support the second variant. */
+ if (reverse_comparison)
+ PUT_CODE (operands[2], reverse_condition (GET_CODE (operands[2])));
+
+ if (which_alternative == 0)
+ {
+ int nullify = INSN_ANNULLED_BRANCH_P (insn);
+ int length = get_attr_length (insn);
+
+ /* If this is a long branch with its delay slot unfilled, set `nullify'
+ as it can nullify the delay slot and save a nop. */
+ if (length == 2 && dbr_sequence_length () == 0)
+ nullify = 1;
+
+ /* If this is a short forward conditional branch which did not get
+ its delay slot filled, the delay slot can still be nullified. */
+ if (! nullify && length == 1 && dbr_sequence_length () == 0)
+ nullify = forward_branch_p (insn);
+
+ /* Handle short versions first. */
+ if (length == 1 && nullify)
+ return "movb,%C2,n %1,%0,%3";
+ else if (length == 1 && ! nullify)
+ return "movb,%C2 %1,%0,%3";
+ else if (length == 2)
+ {
+ /* Handle weird backwards branch with a fulled delay slot
+ which is nullified. */
+ if (dbr_sequence_length () != 0
+ && ! forward_branch_p (insn)
+ && nullify)
+ return "movb,%N2,n %1,%0,.+12\n\ttbl %3,0";
+
+ /* Handle normal cases. */
+ if (nullify)
+ return "or,%N2 %1,%%r0,%0\n\tbl,n %3,0";
+ else
+ return "or,%N2 %1,%%r0,%0\n\tbl %3,0";
+ }
+ else
+ abort();
+ }
+ /* Deal with gross reload from FP register case. */
+ else if (which_alternative == 1)
+ {
+ /* Move loop counter from FP register to MEM then into a GR,
+ increment the GR, store the GR into MEM, and finally reload
+ the FP register from MEM from within the branch's delay slot. */
+ output_asm_insn ("fstws %1,-16(0,%%r30)",operands);
+ if (get_attr_length (insn) == 3)
+ return "comb,%S2 0,%1,%3\n\tfldws -16(0,%%r30),%0";
+ else
+ return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
+ }
+ /* Deal with gross reload from memory case. */
+ else
+ {
+ /* Reload loop counter from memory, the store back to memory
+ happens in the branch's delay slot. */
+ if (get_attr_length (insn) == 2)
+ return "comb,%S2 0,%1,%3\n\tstw %1,%0";
+ else
+ return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tstw %1,%0";
+ }
+}
+
+
extern struct obstack *saveable_obstack;
/* In HPUX 8.0's shared library scheme, special relocations are needed
@@ -3603,3 +3812,22 @@ forward_branch_p (insn)
return (insn == label);
}
+/* Return 1 if OP is an equality comparison, else return 0. */
+int
+eq_neq_comparison_operator (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
+}
+
+/* Return 1 if OP is an operator suitable for use in a movb instruction. */
+int
+movb_comparison_operator (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (GET_CODE (op) == EQ || GET_CODE (op) == NE
+ || GET_CODE (op) == LT || GET_CODE (op) == GE);
+}
+