* v850.c (ep_memory_offset): New function.
(ep_memory_operand, substitute_ep_register, v850_reorg): Call it.
* v850.h (CONST_OK_FOR_*): Add and correct comments.
(CONSTANT_ADDRESS_P): Add comment.
(EXTRA_CONSTRAINT): Define 'U'.
* v850.md: Add comments on bit field instructions.
(addsi3): Delete &r/r/r alternative. Add r/r/U alternative.
(lshrsi3): Use N not J constraint.
* v850.md (v850_tst1+1): New define_split for tst1 instruction.
* v850.c (reg_or_0_operand): Call register_operand.
(reg_or_int5_operand): Likewise.
* v850.h (MASK_BIG_SWITCH, TARGET_BIG_SWITCH): New macros.
(TARGET_SWITCHES): Add "big-switch".
(ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT, CASE_VECTOR_MODE,
ASM_OUTPUT_BEFORE_BASE_LABEL): Add support for TARGET_BIG_SWITCH.
(CASE_DROPS_THROUGH): Comment out.
(CASE_VECTOR_PC_RELATIVE, JUMP_TABLES_IN_TEXT_SECTION): Define.
* v850.md (cmpsi): Delete compare mode.
(casesi): New pattern.
* v850.h (CONST_OK_FOR_N): Delete redundant compare against zero.
* v850.md (ashlsi3): Use SImode not QImode for shift count.
(lshrsi3): Likewise.
* v850.c (print_operand): Add 'c', 'C', and 'z' support. Delete
unreachable switch statement after 'b' support. Remove "b" from
strings for 'b' support.
* v850.md (branch_normal, branch_invert): Change %b to b%b.
v850 patches from Jim.
From-SVN: r15992
+Fri Oct 17 23:48:52 1997 Jim Wilson (wilson@cygnus.com)
+
+ * v850.c (ep_memory_offset): New function.
+ (ep_memory_operand, substitute_ep_register, v850_reorg): Call it.
+
+ * v850.h (CONST_OK_FOR_*): Add and correct comments.
+ (CONSTANT_ADDRESS_P): Add comment.
+ (EXTRA_CONSTRAINT): Define 'U'.
+ * v850.md: Add comments on bit field instructions.
+ (addsi3): Delete &r/r/r alternative. Add r/r/U alternative.
+ (lshrsi3): Use N not J constraint.
+
+ * v850.md (v850_tst1+1): New define_split for tst1 instruction.
+
+ * v850.c (reg_or_0_operand): Call register_operand.
+ (reg_or_int5_operand): Likewise.
+ * v850.h (MASK_BIG_SWITCH, TARGET_BIG_SWITCH): New macros.
+ (TARGET_SWITCHES): Add "big-switch".
+ (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT, CASE_VECTOR_MODE,
+ ASM_OUTPUT_BEFORE_BASE_LABEL): Add support for TARGET_BIG_SWITCH.
+ (CASE_DROPS_THROUGH): Comment out.
+ (CASE_VECTOR_PC_RELATIVE, JUMP_TABLES_IN_TEXT_SECTION): Define.
+ * v850.md (cmpsi): Delete compare mode.
+ (casesi): New pattern.
+
+ * v850.h (CONST_OK_FOR_N): Delete redundant compare against zero.
+ * v850.md (ashlsi3): Use SImode not QImode for shift count.
+ (lshrsi3): Likewise.
+
+ * v850.c (print_operand): Add 'c', 'C', and 'z' support. Delete
+ unreachable switch statement after 'b' support. Remove "b" from
+ strings for 'b' support.
+ * v850.md (branch_normal, branch_invert): Change %b to b%b.
+
Fri Oct 17 23:33:20 1997 Jeffrey A Law (law@cygnus.com)
* Makefile.in (LIBGCC2_CFLAGS): Avoid a backslash then an
{
case 'b':
case 'B':
- switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
+ case 'c':
+ case 'C':
+ switch ((code == 'B' || code == 'C')
+ ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
{
case NE:
- fprintf (file, "bne");
+ if (code == 'c' || code == 'C')
+ fprintf (file, "nz");
+ else
+ fprintf (file, "ne");
break;
case EQ:
- fprintf (file, "be");
+ if (code == 'c' || code == 'C')
+ fprintf (file, "z");
+ else
+ fprintf (file, "e");
break;
case GE:
- fprintf (file, "bge");
+ fprintf (file, "ge");
break;
case GT:
- fprintf (file, "bgt");
+ fprintf (file, "gt");
break;
case LE:
- fprintf (file, "ble");
+ fprintf (file, "le");
break;
case LT:
- fprintf (file, "blt");
+ fprintf (file, "lt");
break;
case GEU:
- fprintf (file, "bnl");
+ fprintf (file, "nl");
break;
case GTU:
- fprintf (file, "bh");
+ fprintf (file, "h");
break;
case LEU:
- fprintf (file, "bnh");
+ fprintf (file, "nh");
break;
case LTU:
- fprintf (file, "bl");
- break;
- default:
- abort ();
- }
- break;
- switch (GET_CODE (x))
- {
- case NE:
- fprintf (file, "be");
- break;
- case EQ:
- fprintf (file, "bne");
- break;
- case GE:
- fprintf (file, "blt");
- break;
- case GT:
- fprintf (file, "bgt");
- break;
- case LE:
- fprintf (file, "ble");
- break;
- case LT:
- fprintf (file, "blt");
- break;
- case GEU:
- fprintf (file, "bnl");
- break;
- case GTU:
- fprintf (file, "bh");
- break;
- case LEU:
- fprintf (file, "bnh");
- break;
- case LTU:
- fprintf (file, "bl");
+ fprintf (file, "l");
break;
default:
abort ();
case '.': /* register r0 */
fputs (reg_names[0], file);
break;
+ case 'z': /* reg or zero */
+ if (x == const0_rtx)
+ fputs (reg_names[0], file);
+ else if (GET_CODE (x) == REG)
+ fputs (reg_names[REGNO (x)], file);
+ else
+ abort ();
+ break;
default:
switch (GET_CODE (x))
{
}
\f
-/* Return true if OP is a valid short EP memory reference */
+/* Return maximum offset supported for a short EP memory reference of mode
+ MODE and signedness UNSIGNEDP. */
int
-ep_memory_operand (op, mode, unsigned_load)
- rtx op;
+ep_memory_offset (mode, unsignedp)
enum machine_mode mode;
- int unsigned_load;
+ int unsignedp;
{
- rtx addr, op0, op1;
- int max_offset;
- int mask;
-
- if (GET_CODE (op) != MEM)
- return FALSE;
+ int max_offset = 0;
- switch (GET_MODE (op))
+ switch (mode)
{
- default:
- return FALSE;
-
case QImode:
- max_offset = (1 << 7);
- mask = 0;
+ max_offset = (1 << 7);
break;
case HImode:
- max_offset = (1 << 8);
- mask = 1;
+ max_offset = (1 << 8);
break;
case SImode:
case SFmode:
max_offset = (1 << 8);
- mask = 3;
break;
}
+ return max_offset;
+}
+
+/* Return true if OP is a valid short EP memory reference */
+
+int
+ep_memory_operand (op, mode, unsigned_load)
+ rtx op;
+ enum machine_mode mode;
+ int unsigned_load;
+{
+ rtx addr, op0, op1;
+ int max_offset;
+ int mask;
+
+ if (GET_CODE (op) != MEM)
+ return FALSE;
+
+ max_offset = ep_memory_offset (mode, unsigned_load);
+
+ mask = GET_MODE_SIZE (mode) - 1;
+
addr = XEXP (op, 0);
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
else if (GET_CODE (op) == CONST_DOUBLE)
return CONST_DOUBLE_OK_FOR_G (op);
- else if (GET_CODE (op) == REG)
- return TRUE;
-
- else if (GET_CODE (op) == SUBREG)
- {
- do {
- op = SUBREG_REG (op);
- } while (GET_CODE (op) == SUBREG);
-
- if (GET_CODE (op) == MEM && !reload_completed)
- return TRUE;
-
- else if (GET_CODE (op) == REG)
- return TRUE;
- }
-
- return FALSE;
+ else
+ return register_operand (op, mode);
}
/* Return true if OP is either a register or a signed five bit integer */
if (GET_CODE (op) == CONST_INT)
return CONST_OK_FOR_J (INTVAL (op));
- else if (GET_CODE (op) == REG)
- return TRUE;
-
- else if (GET_CODE (op) == SUBREG)
- {
- do {
- op = SUBREG_REG (op);
- } while (GET_CODE (op) == SUBREG);
-
- if (GET_CODE (op) == MEM && !reload_completed)
- return TRUE;
-
- else if (GET_CODE (op) == REG)
- return TRUE;
- }
-
- return FALSE;
+ else
+ return register_operand (op, mode);
}
/* Return true if OP is a valid call operand. */
if (pattern)
{
rtx *p_mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
if (GET_CODE (SET_DEST (pattern)) == MEM
&& GET_CODE (SET_SRC (pattern)) == MEM)
&& GET_CODE (XEXP (addr, 0)) == REG
&& REGNO (XEXP (addr, 0)) == regno
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
- && (GET_MODE (*p_mem) != QImode
- || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+ && (((unsigned)INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (*p_mem),
+ unsignedp)))
*p_mem = change_address (*p_mem, VOIDmode,
gen_rtx (PLUS, Pmode,
*p_ep, XEXP (addr, 1)));
rtx src = SET_SRC (pattern);
rtx dest = SET_DEST (pattern);
rtx mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
mem = NULL_RTX;
else
mem = NULL_RTX;
- if (mem && ep_memory_operand (mem, GET_MODE (mem), FALSE))
+ if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
use_ep = TRUE;
else if (!use_ep && mem
else if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == REG
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
- && (GET_MODE (mem) != QImode
- || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+ && (((unsigned)INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (mem), unsignedp)))
{
short_p = TRUE;
regno = REGNO (XEXP (addr, 0));
#define MASK_CPU 0x00000030
#define MASK_V850 0x00000010
+#define MASK_BIG_SWITCH 0x00000100
+
#ifndef MASK_DEFAULT
#define MASK_DEFAULT MASK_V850
#endif
/* Whether to call out-of-line functions to save registers or not. */
#define TARGET_PROLOG_FUNCTION (target_flags & MASK_PROLOG_FUNCTION)
+/* Whether to emit 2 byte per entry or 4 byte per entry switch tables. */
+#define TARGET_BIG_SWITCH (target_flags & MASK_BIG_SWITCH)
+
/* General debug flag */
#define TARGET_DEBUG (target_flags & MASK_DEBUG)
{ "debug", MASK_DEBUG }, \
{ "v850", MASK_V850 }, \
{ "v850", -(MASK_V850 ^ MASK_CPU) }, \
+ { "big-switch", MASK_BIG_SWITCH }, \
EXTRA_SWITCHES \
{ "", TARGET_DEFAULT}}
#define INT_7_BITS(VALUE) ((unsigned) (VALUE) + 0x40 < 0x80)
#define INT_8_BITS(VALUE) ((unsigned) (VALUE) + 0x80 < 0x100)
-/* 0 bits */
+/* zero */
#define CONST_OK_FOR_I(VALUE) ((VALUE) == 0)
-/* 4 bits */
+/* 5 bit signed immediate */
#define CONST_OK_FOR_J(VALUE) ((unsigned) (VALUE) + 0x10 < 0x20)
-/* 15 bits */
+/* 16 bit signed immediate */
#define CONST_OK_FOR_K(VALUE) ((unsigned) (VALUE) + 0x8000 < 0x10000)
+/* valid constant for movhi instruction. */
#define CONST_OK_FOR_L(VALUE) \
(((unsigned) ((int) (VALUE) >> 16) + 0x8000 < 0x10000) \
&& CONST_OK_FOR_I ((VALUE & 0xffff)))
-/* 16 bits */
-#define CONST_OK_FOR_M(VALUE) ((unsigned)(VALUE) < 0x10000
+/* 16 bit unsigned immediate */
+#define CONST_OK_FOR_M(VALUE) ((unsigned)(VALUE) < 0x10000)
+/* 5 bit unsigned immediate in shift instructions */
+#define CONST_OK_FOR_N(VALUE) ((unsigned) (VALUE) <= 31)
-#define CONST_OK_FOR_N(VALUE) ((unsigned) VALUE >= 0 && (unsigned) VALUE <= 31) /* 5 bit signed immediate in shift instructions */
#define CONST_OK_FOR_O(VALUE) 0
#define CONST_OK_FOR_P(VALUE) 0
\f
/* 1 if X is an rtx for a constant that is a valid address. */
+/* ??? This seems too exclusive. May get better code by accepting more
+ possibilities here, in particular, should accept ZDA_NAME SYMBOL_REFs. */
+
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == CONST_INT \
&& CONST_OK_FOR_K (INTVAL (X)))
: (C) == 'R' ? special_symbolref_operand (OP, VOIDmode) \
: (C) == 'S' ? (GET_CODE (OP) == SYMBOL_REF && ! ZDA_NAME_P (XSTR (OP, 0))) \
: (C) == 'T' ? 0 \
- : (C) == 'U' ? 0 \
+ : (C) == 'U' ? ((GET_CODE (OP) == SYMBOL_REF && ZDA_NAME_P (XSTR (OP, 0))) \
+ || (GET_CODE (OP) == CONST \
+ && GET_CODE (XEXP (OP, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (OP, 0), 0)) == SYMBOL_REF \
+ && ZDA_NAME_P (XSTR (XEXP (XEXP (OP, 0), 0), 0)))) \
: 0)
\f
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- asm_fprintf (FILE, "\t%s .L%d\n", ".long", VALUE)
+ asm_fprintf (FILE, "\t%s .L%d\n", \
+ (TARGET_BIG_SWITCH ? ".long" : ".short"), VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
- fprintf (FILE, "\t%s .L%d-.L%d\n", ".long", VALUE, REL)
+ fprintf (FILE, "\t%s .L%d-.L%d\n", \
+ (TARGET_BIG_SWITCH ? ".long" : ".short"), \
+ VALUE, REL)
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
if ((LOG) != 0) \
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
-#define CASE_VECTOR_MODE Pmode
+#define CASE_VECTOR_MODE (TARGET_BIG_SWITCH ? SImode : HImode)
/* Define this if the case instruction drops through after the table
when the index is out of range. Don't define it if the case insn
jumps to the default label instead. */
-#define CASE_DROPS_THROUGH
+/* #define CASE_DROPS_THROUGH */
+
+/* We must use a PC relative entry for small tables. It would be more
+ efficient to use an absolute entry for big tables, but this is not
+ a runtime choice yet. */
+#define CASE_VECTOR_PC_RELATIVE
+
+/* The switch instruction requires that the jump table immediately follow
+ it. */
+#define JUMP_TABLES_IN_TEXT_SECTION
+
+/* svr4.h defines this assuming that 4 byte alignment is required. */
+#undef ASM_OUTPUT_BEFORE_CASE_LABEL
+#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \
+ ASM_OUTPUT_ALIGN ((FILE), (TARGET_BIG_SWITCH ? 2 : 1));
#define WORD_REGISTER_OPERATIONS
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
+;; This replaces ld.b;sar;andi with tst1;setf nz.
+
+;; ??? The zero_extract sets the Z bit to the opposite of what one would
+;; expect. This perhaps should be wrapped in a (eq: X (const_int 0)).
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extract:SI (match_operand:QI 1 "memory_operand" "")
+ (const_int 1)
+ (match_operand 2 "const_int_operand" "")))]
+ ""
+ [(set (cc0) (zero_extract:SI (match_dup 1)
+ (const_int 1)
+ (match_dup 2)))
+ (set (match_dup 0) (ne:SI (cc0) (const_int 0)))])
+
(define_insn "tstsi"
[(set (cc0) (match_operand:SI 0 "register_operand" "r"))]
""
(define_insn "cmpsi"
[(set (cc0)
- (compare:SI (match_operand:SI 0 "register_operand" "r,r")
- (match_operand:SI 1 "reg_or_int5_operand" "r,J")))]
+ (compare (match_operand:SI 0 "register_operand" "r,r")
+ (match_operand:SI 1 "reg_or_int5_operand" "r,J")))]
""
"@
cmp %1,%0
;; ----------------------------------------------------------------------
(define_insn "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,&r")
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
(plus:SI (match_operand:SI 1 "register_operand" "%0,r,r")
- (match_operand:SI 2 "nonmemory_operand" "rJ,K,r")))]
+ (match_operand:SI 2 "nonmemory_operand" "rJ,K,U")))]
""
"@
add %2,%0
addi %2,%1,%0
- mov %1,%0\;add %2,%0"
- [(set_attr "length" "2,4,6")
- (set_attr "cc" "set_zn")])
+ addi %O2(%P2),%1,%0"
+ [(set_attr "length" "2,4,4")
+ (set_attr "cc" "set_zn,set_zn,set_zn")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
-;; Is it worth defining insv and extv for the V850 series?!?
+
+;; ??? Is it worth defining insv and extv for the V850 series?!?
+
+;; An insv pattern would be useful, but does not get used because
+;; store_bit_field never calls insv when storing a constant value into a
+;; single-bit bitfield.
+
+;; extv/extzv patterns would be useful, but do not get used because
+;; optimize_bitfield_compare in fold-const usually converts single
+;; bit extracts into an AND with a mask.
;; -----------------------------------------------------------------
;; Scc INSTRUCTIONS
return 0;
if (get_attr_length (insn) == 2)
- return \"%b1 %l0\";
+ return \"b%b1 %l0\";
else
- return \"%B1 .+6\;jr %l0\";
+ return \"b%B1 .+6\;jr %l0\";
}"
[(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (pc)))
|| GET_CODE (operands[1]) == LT))
return 0;
if (get_attr_length (insn) == 2)
- return \"%B1 %l0\";
+ return \"b%B1 %l0\";
else
- return \"%b1 .+6\;jr %l0\";
+ return \"b%b1 .+6\;jr %l0\";
}"
[(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (pc)))
[(set_attr "length" "2")
(set_attr "cc" "none")])
+(define_expand "casesi"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")
+ (match_operand 3 "" "") (match_operand 4 "" "")]
+ ""
+ "
+{
+ rtx reg = gen_reg_rtx (SImode);
+ rtx tableaddress = gen_reg_rtx (SImode);
+ rtx mem;
+
+ /* Subtract the lower bound from the index. */
+ emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
+ /* Compare the result against the number of table entries. */
+ emit_insn (gen_cmpsi (reg, operands[2]));
+ /* Branch to the default label if out of range of the table. */
+ emit_jump_insn (gen_bgtu (operands[4]));
+
+ /* Shift index for the table array access. */
+ emit_insn (gen_ashlsi3 (reg, reg, GEN_INT (TARGET_BIG_SWITCH ? 2 : 1)));
+ /* Load the table address into a psuedo. */
+ emit_insn (gen_movsi (tableaddress,
+ gen_rtx (LABEL_REF, VOIDmode, operands[3])));
+ /* Add the table address to the index. */
+ emit_insn (gen_addsi3 (reg, reg, tableaddress));
+ /* Load the table entry. */
+ mem = gen_rtx (MEM, CASE_VECTOR_MODE, reg);
+ RTX_UNCHANGING_P (mem);
+ if (! TARGET_BIG_SWITCH)
+ {
+ rtx reg2 = gen_reg_rtx (HImode);
+ emit_insn (gen_movhi (reg2, mem));
+ emit_insn (gen_extendhisi2 (reg, reg2));
+ }
+ else
+ emit_insn (gen_movsi (reg, mem));
+ /* Add the table address. */
+ emit_insn (gen_addsi3 (reg, reg, tableaddress));
+ /* Branch to the switch label. */
+ emit_jump_insn (gen_tablejump (reg, operands[3]));
+ DONE;
+}")
+
;; Call subroutine with no return value.
(define_expand "call"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ashift:SI
(match_operand:SI 1 "register_operand" "0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,N")))]
+ (match_operand:SI 2 "nonmemory_operand" "r,N")))]
""
"@
shl %2,%0
[(set (match_operand:SI 0 "register_operand" "=r,r")
(lshiftrt:SI
(match_operand:SI 1 "register_operand" "0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,J")))]
+ (match_operand:SI 2 "nonmemory_operand" "r,N")))]
""
"@
shr %2,%0