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
This commit is contained in:
parent
5718612fc1
commit
b109290138
3 changed files with 200 additions and 33 deletions
|
@ -382,6 +382,19 @@ arith_double_operand (op, mode)
|
|||
== ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue