Commit 269c14e1 by Doug Evans

h8300.h (SP_AND_G_REGS): Renamed from SP_AND_G_REG.

	* h8300/h8300.h (SP_AND_G_REGS): Renamed from SP_AND_G_REG.
	(CC_DONE_CBIT): Delete.
	(CC_OVERFLOW_0,CC_OVERFLOW_UNUSABLE,CC_NO_CARRY): Define.
	* h8300/h8300.c (cond_string): Delete CC_DONE_CBIT handling.
	(notice_update_cc): Delete CC_CBIT, CC_WHOOPS.  Add CC_SET_ZN_C0.
	(restore_compare_p): New function.
	(shift_one): Use shll instead of shal so overflow bit is usable.
	Set cc_valid bits to cc_status.flags values.
	(emit_a_shift): Set cc_status.flags.
	* h8300/h8300.md (attr cc): Delete whoops,cbit.  Add set_zn_c0.
	(all patterns) Update cc attr setting.
	(tstqi,tsthi,tstsi): Delete CC_DONE_CBIT handling.
	(addhi3,subhi3): Change define_expand to define_insn.
	(branch_true,branch_false): Check if compare needs to be restored.

From-SVN: r11514
parent 4e74d8ec
......@@ -757,12 +757,8 @@ cond_string (code)
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";
......@@ -800,8 +796,7 @@ print_operand (file, x, code)
/* 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)
......@@ -1081,7 +1076,7 @@ print_operand (file, x, 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)]);
......@@ -1271,49 +1266,89 @@ notice_update_cc (body, insn)
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
......@@ -1486,8 +1521,9 @@ enum shift_mode
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
{
......@@ -1507,19 +1543,19 @@ static const struct shift_insn shift_one[2][3][3] =
{
/* 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 }
}
......@@ -1528,21 +1564,21 @@ static const struct shift_insn shift_one[2][3][3] =
{
/* 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 }
}
}
};
......@@ -1911,7 +1947,10 @@ emit_a_shift (insn, operands)
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:
{
......@@ -1934,6 +1973,7 @@ emit_a_shift (insn, operands)
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",
......@@ -1949,6 +1989,7 @@ emit_a_shift (insn, operands)
"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 "";
......
......@@ -322,14 +322,18 @@ do { \
/* The h8 has only one kind of register, but we mustn't do byte by
byte operations on the sp, so we keep it as a different class */
enum reg_class { NO_REGS, LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REG, ALL_REGS, LIM_REG_CLASSES };
enum reg_class {
NO_REGS, LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REGS,
ALL_REGS, LIM_REG_CLASSES
};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{"NO_REGS", "LONG_REGS", "GENERAL_REGS", "SP_REG", "SP_AND_G_REG", "ALL_REGS", "LIM_REGS" }
{ "NO_REGS", "LONG_REGS", "GENERAL_REGS", "SP_REG", "SP_AND_G_REGS", \
"ALL_REGS", "LIM_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
......@@ -340,7 +344,7 @@ enum reg_class { NO_REGS, LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REG, ALL_RE
0x07f, /* LONG_REGS */ \
0x07f, /* GENERAL_REGS */ \
0x080, /* SP_REG */ \
0x0ff, /* SP_AND_G_REG */ \
0x0ff, /* SP_AND_G_REGS */ \
0x1ff, /* ALL_REGS */ \
}
......@@ -971,14 +975,18 @@ extern int current_function_anonymous_args;
Do not alter them if the instruction would not alter the cc's. */
#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN)
#define CC_DONE_CBIT 0400
#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
{ \
if (cc_status.flags & CC_NO_OVERFLOW) \
return NO_OV; \
return NORMAL; \
}
/* The mov,and,or,xor insns always set V to 0. */
#define CC_OVERFLOW_0 0400
/* The add insns don't set overflow in a usable way. */
#define CC_OVERFLOW_UNUSABLE 01000
/* The mov,and,or,xor insns don't set carry. That's ok though as the
Z bit is all we need when doing unsigned comparisons on the result of
these insns (since they're always with 0). However, conditions.h has
CC_NO_OVERFLOW defined for this purpose. Rename it to something more
understandable. */
#define CC_NO_CARRY CC_NO_OVERFLOW
/* ??? Use CC_Z_IN_NOT_C for bld insns? */
/* Control the assembler format that we output. */
......
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