Commit b1092901 by Jeff Law

pa.c (ireg_or_int5_operand): New function.

        * pa.c (ireg_or_int5_operand): New function.
        (output_parallel_movb, output_parallel_addb): Likewise.
        (combinable_copy, combinable_add, following_call): Likewise.
        (pa_adjust_insn_length): Handle parallel unconditional branches.
        (output_movb): Handle case were destination is %sar.
        * pa.h: Declare new functions.
        * pa.md (parallel_branch): New "type" attribute.
        (delay slot descriptions): Don't allow "parallel_branches" in
        delay slots.  Fill "parallel_branches" like "branch" insns.
        (movb patterns): Handle %sar as destination register.

From-SVN: r12382
parent 5718612f
......@@ -383,6 +383,19 @@ arith_double_operand (op, mode)
}
/* Return truth value of whether OP is a integer which fits the
range constraining immediate operands in three-address insns, or
is an integer register. */
int
ireg_or_int5_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
|| (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
}
/* Return truth value of whether OP is a integer which fits the
range constraining immediate operands in three-address insns. */
int
......@@ -3058,6 +3071,10 @@ pa_adjust_insn_length (insn, length)
&& length == 4
&& ! forward_branch_p (insn))
return 4;
else if (GET_CODE (pat) == PARALLEL
&& get_attr_type (insn) == TYPE_PARALLEL_BRANCH
&& length == 4)
return 4;
/* Adjust dbra insn with short backwards conditional branch with
unfilled delay slot -- only for case where counter is in a
general register register. */
......@@ -3071,8 +3088,7 @@ pa_adjust_insn_length (insn, length)
else
return 0;
}
else
return 0;
return 0;
}
/* Print operand X (an rtx) in assembler syntax to file FILE.
......@@ -4364,8 +4380,10 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
output_asm_insn ("stw %1,-16(0,%%r30)",operands);
return "fldws -16(0,%%r30),%0";
}
else
else if (which_alternative == 2)
return "stw %1,%0";
else
return "mtsar %r1";
}
/* Support the second variant. */
......@@ -4432,7 +4450,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
}
/* Deal with gross reload from memory case. */
else
else if (which_alternative == 2)
{
/* Reload loop counter from memory, the store back to memory
happens in the branch's delay slot. */
......@@ -4441,6 +4459,14 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
else
return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tstw %1,%0";
}
/* Handle SAR as a destination. */
else
{
if (get_attr_length (insn) == 8)
return "comb,%S2 0,%1,%3\n\tmtsar %r1";
else
return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tmtsar %r1";
}
}
......@@ -5088,6 +5114,157 @@ jump_in_call_delay (insn)
return 0;
}
/* Output an unconditional move and branch insn. */
char *
output_parallel_movb (operands, length)
rtx *operands;
int length;
{
/* These are the cases in which we win. */
if (length == 4)
return "mov%I1b,tr %1,%0,%2";
/* None of these cases wins, but they don't lose either. */
if (dbr_sequence_length () == 0)
{
/* Nothing in the delay slot, fake it by putting the combined
insn (the copy or add) in the delay slot of a bl. */
if (GET_CODE (operands[1]) == CONST_INT)
return "bl %2,0\n\tldi %1,%0";
else
return "bl %2,0\n\tcopy %1,%0";
}
else
{
/* Something in the delay slot, but we've got a long branch. */
if (GET_CODE (operands[1]) == CONST_INT)
return "ldi %1,%0\n\tbl %2,0";
else
return "copy %1,%0\n\tbl %2,0";
}
}
/* Output an unconditional add and branch insn. */
char *
output_parallel_addb (operands, length)
rtx *operands;
int length;
{
/* To make life easy we want operand0 to be the shared input/output
operand and operand1 to be the readonly operand. */
if (operands[0] == operands[1])
operands[1] = operands[2];
/* These are the cases in which we win. */
if (length == 4)
return "add%I1b,tr %1,%0,%3";
/* None of these cases win, but they don't lose either. */
if (dbr_sequence_length () == 0)
{
/* Nothing in the delay slot, fake it by putting the combined
insn (the copy or add) in the delay slot of a bl. */
return "bl %3,0\n\tadd%I1 %1,%0,%0";
}
else
{
/* Something in the delay slot, but we've got a long branch. */
return "add%I1 %1,%0,%0\n\tbl %3,0";
}
}
/* Return nonzero if INSN represents an integer add which might be
combinable with an unconditional branch. */
combinable_add (insn)
rtx insn;
{
rtx src, dest, prev, pattern = PATTERN (insn);
/* Must be a (set (reg) (plus (reg) (reg/5_bit_int))) */
if (GET_CODE (pattern) != SET
|| GET_CODE (SET_SRC (pattern)) != PLUS
|| GET_CODE (SET_DEST (pattern)) != REG)
return 0;
src = SET_SRC (pattern);
dest = SET_DEST (pattern);
/* Must be an integer add. */
if (GET_MODE (src) != SImode
|| GET_MODE (dest) != SImode)
return 0;
/* Each operand must be an integer register and/or 5 bit immediate. */
if (!ireg_or_int5_operand (dest, VOIDmode)
|| !ireg_or_int5_operand (XEXP (src, 0), VOIDmode)
|| !ireg_or_int5_operand (XEXP (src, 1), VOIDmode))
return 0;
/* The destination must also be one of the sources. */
return (dest == XEXP (src, 0) || dest == XEXP (src, 1));
}
/* Return nonzero if INSN represents an integer load/copy which might be
combinable with an unconditional branch. */
combinable_copy (insn)
rtx insn;
{
rtx src, dest, pattern = PATTERN (insn);
enum machine_mode mode;
/* Must be a (set (reg) (reg/5_bit_int)). */
if (GET_CODE (pattern) != SET)
return 0;
src = SET_SRC (pattern);
dest = SET_DEST (pattern);
/* Must be a mode that corresponds to a single integer register. */
mode = GET_MODE (dest);
if (mode != SImode
&& mode != SFmode
&& mode != HImode
&& mode != QImode)
return 0;
/* Each operand must be a register or 5 bit integer. */
if (!ireg_or_int5_operand (dest, VOIDmode)
|| !ireg_or_int5_operand (src, VOIDmode))
return 0;
return 1;
}
/* Return nonzero if INSN (a jump insn) immediately follows a call. This
is used to discourage creating parallel movb/addb insns since a jump
which immediately follows a call can execute in the delay slot of the
call. */
following_call (insn)
rtx insn;
{
/* Find the previous real insn, skipping NOTEs. */
insn = PREV_INSN (insn);
while (insn && GET_CODE (insn) == NOTE)
insn = PREV_INSN (insn);
/* Check for CALL_INSNs and millicode calls. */
if (insn
&& (GET_CODE (insn) == CALL_INSN
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) != SEQUENCE
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& get_attr_type (insn) == TYPE_MILLI)))
return 1;
return 0;
}
/* We use this hook to perform a PA specific optimization which is difficult
to do in earlier passes.
......
......@@ -2280,6 +2280,8 @@ extern char *output_bb ();
extern char *output_bvb ();
extern char *output_dbra ();
extern char *output_movb ();
extern char *output_parallel_movb ();
extern char *output_parallel_addb ();
extern char *output_return ();
extern char *output_call ();
extern char *output_millicode_call ();
......
......@@ -31,7 +31,7 @@
;; type "binary" insns have two input operands (1,2) and one output (0)
(define_attr "type"
"move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,branch,cbranch,fbranch,call,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli"
"move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,branch,cbranch,fbranch,call,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli,parallel_branch"
(const_string "binary"))
;; Processor type (for scheduling, not code generation) -- this attribute
......@@ -69,7 +69,7 @@
;; For conditional branches.
(define_attr "in_branch_delay" "false,true"
(if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli")
(if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
(eq_attr "length" "4"))
(const_string "true")
(const_string "false")))
......@@ -77,7 +77,7 @@
;; Disallow instructions which use the FPU since they will tie up the FPU
;; even if the instruction is nullified.
(define_attr "in_nullified_branch_delay" "false,true"
(if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl")
(if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,parallel_branch")
(eq_attr "length" "4"))
(const_string "true")
(const_string "false")))
......@@ -85,7 +85,7 @@
;; For calls and millicode calls. Allow unconditional branches in the
;; delay slot.
(define_attr "in_call_delay" "false,true"
(cond [(and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli")
(cond [(and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
(eq_attr "length" "4"))
(const_string "true")
(eq_attr "type" "uncond_branch")
......@@ -96,19 +96,19 @@
(const_string "false")))
;; Unconditional branch and call delay slot description.
(define_delay (eq_attr "type" "uncond_branch,branch,call")
;; Call delay slot description.
(define_delay (eq_attr "type" "uncond_branch,call")
[(eq_attr "in_call_delay" "true") (nil) (nil)])
;; millicode call delay slot description. Note it disallows delay slot
;; when TARGET_PORTABLE_RUNTIME.
;; when TARGET_PORTABLE_RUNTIME is true.
(define_delay (eq_attr "type" "milli")
[(and (eq_attr "in_call_delay" "true")
(eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (const_int 0)))
(nil) (nil)])
;; Unconditional branch, return and other similar instructions.
(define_delay (eq_attr "type" "uncond_branch,branch")
;; Return and other similar instructions.
(define_delay (eq_attr "type" "branch,parallel_branch")
[(eq_attr "in_branch_delay" "true") (nil) (nil)])
;; Floating point conditional branch delay slot description and
......@@ -4878,15 +4878,15 @@
[(set (pc)
(if_then_else
(match_operator 2 "movb_comparison_operator"
[(match_operand:SI 1 "register_operand" "r,r,r") (const_int 0)])
[(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
(label_ref (match_operand 3 "" ""))
(pc)))
(set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m")
(set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
(match_dup 1))]
""
"* return output_movb (operands, insn, which_alternative, 0); "
;; Do not expect to understand this the first time through.
[(set_attr "type" "cbranch,multi,multi")
[(set_attr "type" "cbranch,multi,multi,multi")
(set (attr "length")
(if_then_else (eq_attr "alternative" "0")
;; Loop counter in register case
......@@ -4911,7 +4911,7 @@
(const_int 8184))
(const_int 12)
(const_int 16)))
;; Loop counter in memory case.
;; Loop counter in memory or sar case.
;; Extra goo to deal with additional reload insns.
(if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
......@@ -4924,15 +4924,15 @@
[(set (pc)
(if_then_else
(match_operator 2 "movb_comparison_operator"
[(match_operand:SI 1 "register_operand" "r,r,r") (const_int 0)])
[(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
(pc)
(label_ref (match_operand 3 "" ""))))
(set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m")
(set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
(match_dup 1))]
""
"* return output_movb (operands, insn, which_alternative, 1); "
;; Do not expect to understand this the first time through.
[(set_attr "type" "cbranch,multi,multi")
[(set_attr "type" "cbranch,multi,multi,multi")
(set (attr "length")
(if_then_else (eq_attr "alternative" "0")
;; Loop counter in register case
......@@ -4957,7 +4957,7 @@
(const_int 8184))
(const_int 12)
(const_int 16)))
;; Loop counter in memory case.
;; Loop counter in memory or SAR case.
;; Extra goo to deal with additional reload insns.
(if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
......@@ -5262,18 +5262,6 @@
[(set_attr "type" "multi")
(set_attr "length" "8")])
;; XXX FIXME. The function pointer comparison code is only at the FSF
;; for documentation and merging purposes, it is _NOT_ actually used.
;;
;; I've been trying to get Kenner to deal with the machine independent
;; problems for many months, and for whatever reason nothing ever seems
;; to happen.
;;
;; If you want function pointer comparisons to work, first scream at
;; Kenner to deal with the MI problems, then email me for a hack that
;; will get the job done (law@cygnus.com).
;; Given a function pointer, canonicalize it so it can be
;; reliably compared to another function pointer. */
(define_expand "canonicalize_funcptr_for_compare"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment