diff options
author | Jeff Law <law@gcc.gnu.org> | 1996-07-02 23:34:40 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 1996-07-02 23:34:40 -0600 |
commit | b1092901380ec5872a5122837ea72da9d2f6169b (patch) | |
tree | bc3d0f8594974822b41adcd7a9aa7b0297ae8a46 | |
parent | 5718612fc1929a7d9a3ec02c34eb6999c3d5b738 (diff) | |
download | gcc-b1092901380ec5872a5122837ea72da9d2f6169b.zip gcc-b1092901380ec5872a5122837ea72da9d2f6169b.tar.gz gcc-b1092901380ec5872a5122837ea72da9d2f6169b.tar.bz2 |
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
-rw-r--r-- | gcc/config/pa/pa.c | 185 | ||||
-rw-r--r-- | gcc/config/pa/pa.h | 2 | ||||
-rw-r--r-- | gcc/config/pa/pa.md | 46 |
3 files changed, 200 insertions, 33 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 9cc78a4..76a1b97 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -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. diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index f30da47..a6e9f86 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -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 (); diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 8c081b8..6c10b24 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -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" |