}
/* 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
&& 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. */
else
return 0;
}
- else
- return 0;
+ return 0;
}
/* Print operand X (an rtx) in assembler syntax to file FILE.
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. */
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. */
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";
+ }
}
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.
;; 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
;; 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")))
;; 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")))
;; 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")
(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
[(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
(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))))
[(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
(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))))
[(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"