switch (code)
{
case NE:
- if (cc_prev_status.flags & CC_DONE_CBIT)
- return "cs";
return "ne";
case EQ:
- if (cc_prev_status.flags & CC_DONE_CBIT)
- return "cc";
return "eq";
case GE:
return "ge";
/* This is used for communication between the 'P' and 'U' codes. */
static char *last_p;
- /* This is used for communication between the 'Z' and 'Y' codes. */
- /* ??? 'V' and 'W' use it too. */
+ /* This is used for communication between codes V,W,Z and Y. */
static int bitint;
switch (code)
switch (GET_MODE (x))
{
case QImode:
-#if 0 /* Is it asm ("mov.b %0,r2l", ...) */
+#if 0 /* Is it asm ("mov.b %0,r2l", ...) */
fprintf (file, "%s", byte_reg (x, 0));
#else /* ... or is it asm ("mov.b %0l,r2l", ...) */
fprintf (file, "%s", names_big[REGNO (x)]);
switch (get_attr_cc (insn))
{
case CC_NONE:
- /* Insn does not affect the CC at all */
+ /* Insn does not affect CC at all. */
break;
case CC_NONE_0HIT:
- /* Insn does not change the CC, but the 0't operand has been changed. */
-
+ /* Insn does not change CC, but the 0'th operand has been changed. */
if (cc_status.value1 != 0
&& reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
cc_status.value1 = 0;
-
+ /* ??? Is value2 ever set?. */
if (cc_status.value2 != 0
&& reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
cc_status.value2 = 0;
-
break;
case CC_SET:
- /* Insn sets CC to recog_operand[0], but overflow is impossible. */
+ /* Insn sets the Z,N flags of CC to recog_operand[0].
+ V is always set to 0. C may or may not be set to 0 but that's ok
+ because alter_cond will change tests to use EQ/NE. */
CC_STATUS_INIT;
- cc_status.flags |= CC_NO_OVERFLOW;
+ cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
cc_status.value1 = recog_operand[0];
break;
- case CC_COMPARE:
- /* The insn is a compare instruction */
+ case CC_SET_ZN_C0:
+ /* Insn sets the Z,N flags of CC to recog_operand[0].
+ The V flag is unusable. The C flag may or may not be known but
+ that's ok because alter_cond will change tests to use EQ/NE. */
CC_STATUS_INIT;
- cc_status.value1 = SET_SRC (body);
+ cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
+ cc_status.value1 = recog_operand[0];
break;
- case CC_CBIT:
+ case CC_COMPARE:
+ /* The insn is a compare instruction. */
CC_STATUS_INIT;
- cc_status.flags |= CC_DONE_CBIT;
- cc_status.value1 = 0;
+ cc_status.value1 = SET_SRC (body);
break;
- case CC_WHOOPS:
case CC_CLOBBER:
- /* Insn clobbers CC. */
+ /* Insn doesn't leave CC in a usable state. */
CC_STATUS_INIT;
break;
}
}
+/* Return 1 if a previous compare needs to be re-issued. This will happen
+ if the compare was deleted because the previous insn set it, but the
+ branch needs CC flags not set.
+
+ OP is the comparison being performed. */
+
+int
+restore_compare_p (op)
+ rtx op;
+{
+ switch (GET_CODE (op))
+ {
+ case EQ:
+ case NE:
+ break;
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ if (cc_status.flags & CC_OVERFLOW_UNUSABLE)
+ return 1;
+ break;
+ case LTU:
+ case LEU:
+ case GTU:
+ case GEU:
+ /* If the carry flag isn't usable, the test should have been changed
+ by alter_cond. */
+ if (cc_status.flags & CC_NO_CARRY)
+ abort ();
+ break;
+ default:
+ abort ();
+ }
+
+ return 0;
+}
+
/* Recognize valid operators for bit instructions */
int
QIshift, HIshift, SIshift
};
-/* For single bit shift insns, record assembler and whether the condition code
- is valid afterwards. */
+/* For single bit shift insns, record assembler and what bits of the
+ condition code are valid afterwards (represented as various CC_FOO
+ bits, 0 means CC isn't left in a usable state). */
struct shift_insn
{
{
/* SHIFT_ASHIFT */
{
- { "shal %X0", 1 },
- { "add.w %T0,%T0\t; shal.w", 1 },
+ { "shll %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+ { "add.w %T0,%T0\t; shal.w", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
{ "add.w %f0,%f0\t; shal.l\n\taddx %y0,%y0\n\taddx %z0,%z0\t; end shal.l", 0 }
},
/* SHIFT_LSHIFTRT */
{
- { "shlr %X0", 1 },
+ { "shlr %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
{ "shlr %t0\t; shlr.w\n\trotxr %s0\t; end shlr.w", 0 },
{ "shlr %z0\t; shlr.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shlr.l", 0 }
},
/* SHIFT_ASHIFTRT */
{
- { "shar %X0", 1 },
+ { "shar %X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
{ "shar %t0\t; shar.w\n\trotxr %s0\t; end shar.w", 0 },
{ "shar %z0\t; shar.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shar.l", 0 }
}
{
/* SHIFT_ASHIFT */
{
- { "shal.b %X0", 1 },
- { "shal.w %T0", 1 },
- { "shal.l %S0", 1 }
+ { "shll.b %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+ { "shll.w %T0", CC_OVERFLOW_0 | CC_NO_CARRY },
+ { "shll.l %S0", CC_OVERFLOW_0 | CC_NO_CARRY }
},
/* SHIFT_LSHIFTRT */
{
- { "shlr.b %X0", 1 },
- { "shlr.w %T0", 1 },
- { "shlr.l %S0", 1 }
+ { "shlr.b %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+ { "shlr.w %T0", CC_OVERFLOW_0 | CC_NO_CARRY },
+ { "shlr.l %S0", CC_OVERFLOW_0 | CC_NO_CARRY }
},
/* SHIFT_ASHIFTRT */
{
- { "shar.b %X0", 1 },
- { "shar.w %T0", 1 },
- { "shar.l %S0", 1 }
+ { "shar.b %X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
+ { "shar.w %T0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
+ { "shar.l %S0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY }
}
}
};
while (--n >= 0)
output_asm_insn (assembler, operands);
if (cc_valid)
- cc_status.value1 = operands[0];
+ {
+ cc_status.value1 = operands[0];
+ cc_status.flags |= cc_valid;
+ }
return "";
case SHIFT_ROT_AND:
{
sprintf (insn_buf, "and #%d,%%X0\t; end shift %d via rotate+and",
mask, n);
cc_status.value1 = operands[0];
+ cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
break;
case HImode:
sprintf (insn_buf, "and #%d,%%s0\n\tand #%d,%%t0\t; end shift %d via rotate+and",
"bwl"[shift_mode], mask,
mode == QImode ? 'X' : mode == HImode ? 'T' : 'S');
cc_status.value1 = operands[0];
+ cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
}
output_asm_insn (insn_buf, operands);
return "";
;; GCC machine description for Hitachi H8/300
-;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
;; Contributed by Steve Chamberlain (sac@cygnus.com),
;; Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
-
;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.
(eq_attr "type" "call") (const_int 4)]
(const_int 200)))
-(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops,cbit"
- (const_string "whoops"))
-
+;; Condition code settings.
+;; none - insn does not affect cc
+;; none_0hit - insn does not affect cc but it does modify operand 0
+;; This attribute is used to keep track of when operand 0 changes.
+;; See the description of NOTICE_UPDATE_CC for more info.
+;; set - insn sets flags z,n. v,c are set to 0.
+;; (c may not really be set to 0 but that's ok, we don't need it anyway).
+;; set_zn_c0 - insn sets z,n to usable values. v is unknown. c may or may not
+;; be known (if it isn't that's ok, we don't need it anyway).
+;; compare - compare instruction
+;; clobber - value of cc is unknown
+(define_attr "cc" "none,none_0hit,set,set_zn_c0,compare,clobber"
+ (const_string "clobber"))
+\f
;; ----------------------------------------------------------------------
;; MOVE INSTRUCTIONS
;; ----------------------------------------------------------------------
(set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
(set_attr "cc" "set")])
+;; ??? Use of the `c' constraint doesn't seem right.
(define_insn "movqi_internal"
[(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<,r")
(match_operand:QI 1 "general_operand_src" "I,r>,io,r,r,c"))]
- "register_operand (operands[0],QImode) || register_operand (operands[1], QImode)"
+ "register_operand (operands[0],QImode)
+ || register_operand (operands[1], QImode)"
"@
sub.b %X0,%X0
mov.b %X1,%X0
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))
(const_int 4)])
- (set_attr "cc" "set,set,set,set,set,none")])
+ (set_attr "cc" "set_zn_c0,set,set,set,set,clobber")])
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand_dst" "")
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0,set,set,set,set")])
;; movhi
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0,set,set,set,set")])
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand_dst" "")
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
(if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0,set,set,set,set")])
;; movsi
mov.l %S1,%S0"
[(set_attr "type" "move")
(set_attr "length" "2,2,8,8,4,4")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
(define_insn "movsf_h8300h"
[(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r")
mov.l %S1,%S0"
[(set_attr "type" "move")
(set_attr "length" "2,2,8,8,4,4")
- (set_attr "cc" "set")])
-
+ (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
+\f
;; ----------------------------------------------------------------------
;; TEST INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "tstqi"
[(set (cc0) (match_operand:QI 0 "register_operand" "ra"))]
""
- "*
-{
- /* ??? I don't think this is right. --Jim */
- if (cc_prev_status.flags & CC_DONE_CBIT)
- return \"btst #0,%X0\";
- else
- return \"cmp.b #0,%X0\";
-}"
+ "cmp.b #0,%X0"
[(set_attr "type" "arith")
- (set_attr "length" "4")
+ (set_attr "length" "2")
(set_attr "cc" "set")])
(define_insn "tsthi"
[(set (cc0) (match_operand:HI 0 "general_operand" "ra"))]
""
- "*
-{
- /* ??? I don't think this is right. --Jim */
- if (cc_prev_status.flags & CC_DONE_CBIT)
- return \"btst #0,%0l\";
- else
- return \"mov.w %T0,%T0\";
-}"
+ "mov.w %T0,%T0"
[(set_attr "type" "arith")
- (set_attr "length" "4")
+ (set_attr "length" "2")
(set_attr "cc" "set")])
(define_insn "tstsi"
[(set (cc0) (match_operand:SI 0 "general_operand" "ra"))]
"TARGET_H8300H"
- "*
-{
- /* ??? I don't think this is right. --Jim */
- if (cc_prev_status.flags & CC_DONE_CBIT)
- return \"btst #0,%0l\";
- else
- return \"mov.l %S0,%S0\";
-}"
+ "mov.l %S0,%S0"
[(set_attr "type" "arith")
- (set_attr "length" "4")
+ (set_attr "length" "2")
(set_attr "cc" "set")])
(define_insn "cmpqi"
[(set_attr "type" "arith")
(set_attr "length" "2")
(set_attr "cc" "compare")])
-
+\f
;; ----------------------------------------------------------------------
;; ADD INSTRUCTIONS
;; ----------------------------------------------------------------------
"add.b %X2,%X0"
[(set_attr "type" "arith")
(set_attr "length" "2")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0")])
-;; ??? adds operates on the 32bit register. We can use it because we don't
+;; h8300h: adds operates on the 32bit register. We can use it because we don't
;; use the e0-7 registers.
;; ??? 4 can be handled in one insn on the 300h.
-(define_insn "addhi3_internal"
+(define_insn "addhi3"
[(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra")
(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
(match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))]
add.w %T2,%T0"
[(set_attr "type" "arith,multi,arith,multi,multi,arith")
(set_attr "length" "2,4,2,4,4,2")
- (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")])
-
-;; ??? Why is this here?
-(define_expand "addhi3"
- [(set (match_operand:HI 0 "register_operand" "")
- (plus:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:HI 2 "nonmemory_operand" "")))]
- ""
- "")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set_zn_c0")])
(define_expand "addsi3"
[(set (match_operand:SI 0 "register_operand" "")
add.l %S2,%S0"
[(set_attr "type" "multi,multi,multi,multi,arith,arith")
(set_attr "length" "2,4,2,4,6,2")
- (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,clobber")])
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,set_zn_c0,set_zn_c0")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
add.b %G2,%X0"
[(set_attr "type" "arith")
(set_attr "length" "2")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0")])
-;; ??? subs operates on the 32bit register. We can use it because we don't
+;; h8300h: subs operates on the 32bit register. We can use it because we don't
;; use the e0-7 registers.
;; ??? 4 can be handled in one insn on the 300h.
;; ??? The fourth alternative can use sub.w on the 300h.
;; ??? Should the 'n' constraint be an 'i' here?
-(define_insn "subhi3_internal"
+(define_insn "subhi3"
[(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r")
(minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
(match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))]
add.b %E2,%s0\;addx %F2,%t0 ; -%0"
[(set_attr "type" "multi")
(set_attr "length" "2,4,2,4")
- (set_attr "cc" "none_0hit,none_0hit,set,clobber")])
-
-;; ??? Why is this here?
-(define_expand "subhi3"
- [(set (match_operand:HI 0 "register_operand" "")
- (minus:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:HI 2 "nonmemory_operand" "")))]
- ""
- "")
+ (set_attr "cc" "none_0hit,none_0hit,set_zn_c0,clobber")])
(define_expand "subsi3"
[(set (match_operand:SI 0 "register_operand" "")
sub.l %S2,%S0"
[(set_attr "type" "multi")
(set_attr "length" "2,4,2,6")
- (set_attr "cc" "none_0hit,none_0hit,set,set")])
-
+ (set_attr "cc" "none_0hit,none_0hit,set_zn_c0,set_zn_c0")])
+\f
;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
;; ----------------------------------------------------------------------
"mulxs.b %X2,%T0"
[(set_attr "type" "multi")
(set_attr "length" "4")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0")])
(define_insn "mulhisi3"
[(set (match_operand:SI 0 "register_operand" "=r")
"mulxs.w %T2,%S0"
[(set_attr "type" "multi")
(set_attr "length" "4")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0")])
(define_insn "umulqihi3"
[(set (match_operand:HI 0 "register_operand" "=r")
[(set_attr "type" "multi")
(set_attr "length" "6")
(set_attr "cc" "clobber")])
-
+\f
;; ----------------------------------------------------------------------
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------
}")
;; ??? Should have a bclr case here also.
+;; ??? This should be symmetric with iorhi3.
(define_insn "andhi3"
[(set (match_operand:HI 0 "register_operand" "=r")
and %S2,%S0"
[(set_attr "type" "arith")
(set_attr "length" "4,6")
- (set_attr "cc" "clobber")])
+ (set_attr "cc" "set")])
;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
}")
;; ??? Should have a bset case here also.
+;; ??? This should be symmetric with andhi3.
(define_insn "iorhi3"
[(set (match_operand:HI 0 "general_operand" "=r,r")
DONE;
}")
+;; ??? This should be symmetric with andhi3.
+
(define_insn "xorhi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(xor:HI (match_operand:HI 1 "general_operand" "%0")
xor %S2,%S0"
[(set_attr "type" "arith")
(set_attr "length" "4,6")
- (set_attr "cc" "clobber")])
-
+ (set_attr "cc" "set")])
+\f
;; ----------------------------------------------------------------------
;; NEGATION INSTRUCTIONS
;; ----------------------------------------------------------------------
"neg %X0"
[(set_attr "type" "arith")
(set_attr "length" "2")
- (set_attr "cc" "clobber")])
+ (set_attr "cc" "set_zn_c0")])
(define_expand "neghi2"
[(set (match_operand:HI 0 "register_operand" "=r")
"neg %T0"
[(set_attr "type" "arith")
(set_attr "length" "2")
- (set_attr "cc" "clobber")])
+ (set_attr "cc" "set_zn_c0")])
(define_expand "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
"neg %S0"
[(set_attr "type" "arith")
(set_attr "length" "2")
- (set_attr "cc" "clobber")])
+ (set_attr "cc" "set_zn_c0")])
;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ??? length is wrong for 300h
(set_attr "length" "8")
(set_attr "cc" "clobber")])
-
+\f
;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------
""
"*
{
+ /* If we erroneously deleted a compare insn (which can happen if we need
+ CC bits set that aren't), emit the compare. */
+ if (restore_compare_p (operands[1]))
+ return 0;
+
if (get_attr_length (insn) == 2)
return \"b%j1 %l0\";
else if (get_attr_length (insn) == 4)
;; ??? We don't take advantage of 16 bit relative jumps in the 300h.
"*
{
+ /* If we erroneously deleted a compare insn (which can happen if we need
+ CC bits set that aren't), emit the compare. */
+ if (restore_compare_p (operands[1]))
+ return 0;
+
if (get_attr_length (insn) == 2)
return \"b%k1 %l0\";
else if (get_attr_length (insn) == 4)
;; This is a define expand, because pointers may be either 16 or 32 bits.
-;(define_insn "indirect_jump"
-; [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
-; ""
-; "jmp @%0"
-; [(set_attr "type" "branch")
-; (set_attr "cc" "none")
-; (set_attr "length" "2")])
-
(define_expand "indirect_jump"
[(set (pc) (match_operand 0 "jump_address_operand" "Vr"))]
""
[(set_attr "type" "multi")
(set_attr "cc" "none")
(set_attr "length" "2")])
-
+\f
;; ----------------------------------------------------------------------
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
}"
[(set_attr "length" "10")
(set_attr "cc" "clobber")])
-
+\f
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want. Emit_a_shift is free to tweak cc_status as desired.
(set_attr "cc" "clobber")])
-
+\f
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
;; The H8/300 has given 1/8th of its opcode space to bitfield
-;; instructions so let's use them as well as we can
+;; instructions so let's use them as well as we can.
;; BCC and BCS patterns.
operands[1] = mem;
}
}")
-
+\f
;; -----------------------------------------------------------------
;; STACK POINTER MANIPULATIONS
;; -----------------------------------------------------------------
"mov.w %T1,%T0\;add.w %T2,%T0"
[(set_attr "type" "arith")
(set_attr "length" "6")
- (set_attr "cc" "set")])
+ (set_attr "cc" "set_zn_c0")])
;; -------------------------------------------
DONE;
}")
-
+\f
;; ----------------------------------------------
;; Peepholes go at the end.
;; ----------------------------------------------
""
"mov.b %X2,%X0\;bset %X1,%X0")
-
(define_insn "fancybclr4"
[(set (match_operand:QI 0 "general_operand" "=Ur,Ur")
(and:QI