aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/mn10300/mn10300.c182
-rw-r--r--gcc/config/mn10300/mn10300.h59
-rw-r--r--gcc/config/mn10300/mn10300.md331
3 files changed, 518 insertions, 54 deletions
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 13a9774..027a8e7 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -49,27 +49,6 @@ asm_file_start (file)
}
-int
-const_costs (r, c)
- rtx r;
- enum rtx_code c;
-{
- switch (c)
- {
- case CONST_INT:
- if (INT_8_BITS (INTVAL (r)))
- return 0;
- else if (INT_16_BITS (INTVAL (r)))
- return 1;
- else
- return 2;
- case CONST_DOUBLE:
- return 8;
- default:
- return 4;
- }
-}
-
/* Print operand X using operand code CODE to assembly language output file
FILE. */
@@ -134,6 +113,123 @@ print_operand (file, x, code)
print_operand (file, x, 0);
break;
+ /* These are the least significant word in a 64bit value. */
+ case 'L':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ break;
+
+ case SUBREG:
+ fprintf (file, "%s",
+ reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]);
+ break;
+
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
+
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ print_operand_address (file, GEN_INT (val[0]));
+ break;;
+ case SFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]);
+ print_operand_address (file, GEN_INT (val[0]));
+ break;;
+ case VOIDmode:
+ case DImode:
+ print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_LOW (x)));
+ break;
+ }
+ break;
+ }
+
+ case CONST_INT:
+ print_operand_address (file, x);
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ /* Similarly, but for the most significant word. */
+ case 'H':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ x = adj_offsettable_operand (x, 4);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ break;
+
+ case SUBREG:
+ fprintf (file, "%s",
+ reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1);
+ break;
+
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
+
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ print_operand_address (file, GEN_INT (val[1]));
+ break;;
+ case SFmode:
+ abort ();
+ case VOIDmode:
+ case DImode:
+ print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_HIGH (x)));
+ break;
+ }
+ break;
+ }
+
+ case CONST_INT:
+ if (INTVAL (x) < 0)
+ print_operand_address (file, GEN_INT (-1));
+ else
+ print_operand_address (file, GEN_INT (0));
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case 'A':
+ fputc ('(', file);
+ if (GET_CODE (XEXP (x, 0)) == REG)
+ output_address (gen_rtx (PLUS, SImode, XEXP (x, 0), GEN_INT (0)));
+ else
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
default:
switch (GET_CODE (x))
{
@@ -143,6 +239,10 @@ print_operand (file, x, code)
fputc (')', file);
break;
+ case PLUS:
+ output_address (x);
+ break;
+
case REG:
fprintf (file, "%s", reg_names[REGNO (x)]);
break;
@@ -152,6 +252,18 @@ print_operand (file, x, code)
reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]);
break;
+ /* This will only be single precision.... */
+ case CONST_DOUBLE:
+ {
+ unsigned long val;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ print_operand_address (file, GEN_INT (val));
+ break;
+ }
+
case CONST_INT:
case SYMBOL_REF:
case CONST:
@@ -208,6 +320,20 @@ print_operand_address (file, addr)
}
}
+int
+can_use_return_insn ()
+{
+ int size = get_frame_size ();
+
+ return (reload_completed
+ && size == 0
+ && !regs_ever_live[2]
+ && !regs_ever_live[3]
+ && !regs_ever_live[6]
+ && !regs_ever_live[7]
+ && !frame_pointer_needed);
+}
+
void
expand_prologue ()
{
@@ -262,10 +388,16 @@ expand_epilogue ()
else
{
if (size)
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (size)));
- emit_jump_insn (gen_return_internal ());
+ {
+ emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (size)));
+ emit_jump_insn (gen_return_internal ());
+ }
+ else
+ {
+ emit_jump_insn (gen_return ());
+ }
}
}
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 2a49eb1..1cac33a 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -305,13 +305,15 @@ enum reg_class {
#define CONST_OK_FOR_K(VALUE) ((VALUE) == 2)
#define CONST_OK_FOR_L(VALUE) ((VALUE) == 4)
#define CONST_OK_FOR_M(VALUE) ((VALUE) == 3)
+#define CONST_OK_FOR_N(VALUE) ((VALUE) == 255 || (VALUE) == 65535)
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? CONST_OK_FOR_I (VALUE) : \
(C) == 'J' ? CONST_OK_FOR_J (VALUE) : \
(C) == 'K' ? CONST_OK_FOR_K (VALUE) : \
(C) == 'L' ? CONST_OK_FOR_L (VALUE) : \
- (C) == 'M' ? CONST_OK_FOR_M (VALUE) : 0)
+ (C) == 'M' ? CONST_OK_FOR_M (VALUE) : \
+ (C) == 'N' ? CONST_OK_FOR_N (VALUE) : 0)
/* Similar, but for floating constants, and defining letters G and H.
@@ -319,7 +321,9 @@ enum reg_class {
`G' is a floating-point zero. */
-#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'G' ? (GET_MODE_CLASS (GET_MODE (VALUE)) == MODE_FLOAT \
+ && (VALUE) == CONST0_RTX (GET_MODE (VALUE))) : 0)
/* Stack layout; function entry, exit and calling. */
@@ -565,8 +569,22 @@ enum reg_class {
/* Extra constraints. */
+#define OK_FOR_R(OP) \
+ (GET_CODE (OP) == MEM \
+ && GET_MODE (OP) == QImode \
+ && (CONSTANT_ADDRESS_P (XEXP (OP, 0)) \
+ || (GET_CODE (XEXP (OP, 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (OP, 0)) \
+ && XEXP (OP, 0) != stack_pointer_rtx) \
+ || (GET_CODE (XEXP (OP, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (OP, 0), 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (XEXP (OP, 0), 0)) \
+ && XEXP (XEXP (OP, 0), 0) != stack_pointer_rtx \
+ && GET_CODE (XEXP (XEXP (OP, 0), 1)) == CONST_INT \
+ && INT_8_BITS (INTVAL (XEXP (XEXP (OP, 0), 1))))))
+
#define EXTRA_CONSTRAINT(OP, C) \
- ((C) == 'S' ? GET_CODE (OP) == SYMBOL_REF : 0)
+ ((C) == 'R' ? OK_FOR_R (OP) : (C) == 'S' ? GET_CODE (OP) == SYMBOL_REF : 0)
/* Maximum number of registers that can appear in a valid memory address. */
@@ -635,10 +653,11 @@ enum reg_class {
base = XEXP (X, 1), index = XEXP (X, 0); \
if (base != 0 && index != 0) \
{ \
- if (GET_CODE (index) == CONST_INT) \
+ if (CONSTANT_ADDRESS_P (index)) \
goto ADDR; \
if (REG_P (index) \
- && REG_OK_FOR_INDEX_P (index)) \
+ && REG_OK_FOR_INDEX_P (index) \
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (word_mode)) \
goto ADDR; \
} \
} \
@@ -668,8 +687,7 @@ enum reg_class {
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-#define LEGITIMATE_CONSTANT_P(X) \
- (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT) \
+#define LEGITIMATE_CONSTANT_P(X) 1
/* Tell final.c how to eliminate redundant test instructions. */
@@ -691,8 +709,31 @@ enum reg_class {
return it with a return statement. Otherwise, break from the switch. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
- default: { int _zxy= const_costs(RTX, CODE); \
- if(_zxy) return _zxy; break;}
+ case CONST_INT: \
+ /* Zeros are extremely cheap. */ \
+ if (INTVAL (RTX) == 0 && OUTER_CODE == SET) \
+ return 0; \
+ /* If it fits in 8 bits, then it's still relatively cheap. */ \
+ if (INT_8_BITS (INTVAL (RTX))) \
+ return 1; \
+ /* This is the "base" cost, includes constants where either the \
+ upper or lower 16bits are all zeros. */ \
+ if (INT_16_BITS (INTVAL (RTX)) \
+ || (INTVAL (RTX) & 0xffff) == 0 \
+ || (INTVAL (RTX) & 0xffff0000) == 0) \
+ return 2; \
+ return 4; \
+ /* These are more costly than a CONST_INT, but we can relax them, \
+ so they're less costly than a CONST_DOUBLE. */ \
+ case CONST: \
+ case LABEL_REF: \
+ case SYMBOL_REF: \
+ return 6; \
+ /* We don't optimize CONST_DOUBLEs well nor do we relax them well, \
+ so their cost is very high. */ \
+ case CONST_DOUBLE: \
+ return 8;
+
#define REGISTER_MOVE_COST(CLASS1, CLASS2) (CLASS1 != CLASS2 ? 4 : 0)
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 3089e8a..bdc65c8 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -119,10 +119,9 @@
operands[1] = copy_to_mode_reg (SImode, operand1);
}")
-;; We could improve loading of some constants with a little work.
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a,a,x")
- (match_operand:SI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim,x,a"))]
+ [(set (match_operand:SI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a,aR,x")
+ (match_operand:SI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim,x,aR"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
"@
@@ -153,7 +152,6 @@
operands[1] = copy_to_mode_reg (SFmode, operand1);
}")
-;; We could improve loading of some constants with a little work.
(define_insn ""
[(set (match_operand:SF 0 "general_operand" "=d,a,d,dam,da")
(match_operand:SF 1 "general_operand" "0,0,G,da,daim"))]
@@ -167,6 +165,69 @@
mov %1,%0"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit")])
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register */
+ if (!register_operand (operand1, DImode)
+ && !register_operand (operand0, DImode))
+ operands[1] = copy_to_mode_reg (DImode, operand1);
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
+ (match_operand:DI 1 "general_operand" "0,0,I,d,a,d,a,dim,aim,dim,aim"))]
+ "register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode)"
+ "@
+ nop
+ nop
+ clr %L0\;clr %H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register */
+ if (!register_operand (operand1, DFmode)
+ && !register_operand (operand0, DFmode))
+ operands[1] = copy_to_mode_reg (DFmode, operand1);
+}")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "general_operand" "=d,a,d,dm,dm,am,am,d,d,a,a")
+ (match_operand:DF 1 "general_operand" "0,0,G,d,a,d,a,dim,aim,dim,aim"))]
+ "register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode)"
+ "@
+ nop
+ nop
+ clr %L0\;clr %H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0
+ mov %L1,%L0\;mov %H1,%H0"
+ [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+
+
;; ----------------------------------------------------------------------
;; TEST INSTRUCTIONS
@@ -182,8 +243,8 @@
(define_insn "cmpsi"
[(set (cc0)
- (compare:SI (match_operand:SI 0 "register_operand" "da")
- (match_operand:SI 1 "register_operand" "dai")))]
+ (compare (match_operand:SI 0 "register_operand" "da")
+ (match_operand:SI 1 "nonmemory_operand" "dai")))]
""
"cmp %1,%0"
[(set_attr "cc" "compare")])
@@ -193,9 +254,9 @@
;; ----------------------------------------------------------------------
(define_expand "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=da,a,da,x")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
- (match_operand:SI 2 "nonmemory_operand" "J,L,dai,i")))]
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))]
""
"
{
@@ -225,6 +286,48 @@
add %2,%0"
[(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit")])
+(define_expand "adddi3"
+ [(set (reg:DI 0) (match_operand:DI 1 "register_operand" ""))
+ (set (reg:DI 2) (match_operand:DI 2 "nonmemory_operand" ""))
+ (set (reg:DI 0) (plus:DI (reg:DI 0) (reg:DI 2)))
+ (set (match_operand:DI 0 "register_operand" "") (reg:DI 0))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ rtx reg0 = gen_rtx (REG, DImode, 0);
+
+ emit_move_insn (reg0, operands[1]);
+ emit_insn (gen_adddi3_const (operands[2]));
+ emit_move_insn (operands[0], reg0);
+ DONE;
+ }
+}")
+
+;; The general adddi3 pattern.
+(define_insn ""
+ [(set (reg:DI 0) (plus:DI (reg:DI 0) (reg:DI 2)))]
+ ""
+ "add d2,d0\;addc d3,d1"
+ [(set_attr "cc" "clobber")])
+
+;; adddi3 with on operand being a constant.
+(define_insn "adddi3_const"
+ [(set (reg:DI 0)
+ (plus:DI (reg:DI 0) (match_operand:DI 0 "const_int_operand" "i")))
+ (clobber (reg:DI 2))]
+ ""
+ "*
+{
+ long value = INTVAL (operands[0]);
+
+ if (value < 0)
+ return \"mov -1,d2\;add %0,d0\;addc d2,d1\";
+ else
+ return \"clr d2\;add %0,d0\;addc d2,d1\";
+}"
+ [(set_attr "cc" "clobber")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
;; ----------------------------------------------------------------------
@@ -232,7 +335,7 @@
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=da")
(minus:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "register_operand" "dai")))]
+ (match_operand:SI 2 "nonmemory_operand" "dai")))]
""
"sub %2,%0"
[(set_attr "cc" "set_zn_c0")])
@@ -251,6 +354,19 @@
DONE;
}")
+(define_expand "subdi3"
+ [(set (reg:DI 0) (match_operand:DI 1 "register_operand" ""))
+ (set (reg:DI 2) (match_operand:DI 2 "nonmemory_operand" ""))
+ (set (reg:DI 0) (minus:DI (reg:DI 0) (reg:DI 2)))
+ (set (match_operand:DI 0 "register_operand" "") (reg:DI 0))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (reg:DI 0) (minus:DI (reg:DI 0) (reg:DI 2)))]
+ ""
+ "sub d2,d0\;subc d3,d1"
+ [(set_attr "cc" "clobber")])
;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
@@ -304,12 +420,19 @@
;; ----------------------------------------------------------------------
(define_insn "andsi3"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (and:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "nonmemory_operand" "di")))]
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "nonmemory_operand" "N,di")))]
""
- "and %2,%0"
- [(set_attr "cc" "set_zn_c0")])
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff)
+ return \"extbu %0\";
+ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff)
+ return \"exthu %0\";
+ return \"and %2,%0\";
+}"
+ [(set_attr "cc" "none_0hit,set_zn_c0")])
;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
@@ -349,9 +472,127 @@
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
-;; Is it worth defining insv and extv for the MN10300 series?!?
-;; probably so.
+
+;; These set/clear memory in byte sized chunks.
+;;
+;; They are no smaller/faster than loading the value into a register
+;; and storing the register, but they don't need a scratch register
+;; which may allow for better code generation.
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=R,d") (const_int 0))]
+ ""
+ "@
+ bclr 255,%A0
+ clr %0"
+ [(set_attr "cc" "clobber")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=R,d") (const_int -1))]
+ ""
+ "@
+ bset 255,%A0
+ mov -1,%0"
+ [(set_attr "cc" "clobber,none_0hit")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=R,d")
+ (subreg:QI
+ (and:SI (subreg:SI (match_dup 0) 0)
+ (match_operand:SI 1 "const_int_operand" "i,i")) 0))]
+ ""
+ "@
+ bclr %N1,%A0
+ and %1,%0"
+ [(set_attr "cc" "clobber,set_zn_c0")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "general_operand" "=R,d")
+ (subreg:QI
+ (ior:SI (subreg:SI (match_dup 0) 0)
+ (match_operand:SI 1 "const_int_operand" "i,i")) 0))]
+ ""
+ "@
+ bset %1,%A0
+ or %1,%0"
+ [(set_attr "cc" "clobber")])
+
+(define_insn ""
+ [(set (cc0)
+ (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" "")))]
+ ""
+ "*
+{
+ int len = INTVAL (operands[1]);
+ int bit = INTVAL (operands[2]);
+ int mask = 0;
+ rtx xoperands[2];
+
+ while (len > 0)
+ {
+ mask |= (1 << bit);
+ bit++;
+ len--;
+ }
+
+ xoperands[0] = operands[0];
+ xoperands[1] = GEN_INT (mask);
+ output_asm_insn (\"btst %1,%0\", xoperands);
+ return \"\";
+}"
+ [(set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+ [(set (cc0)
+ (zero_extract:SI (match_operand:QI 0 "general_operand" "R,d")
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" "")))]
+ "INTVAL (operands[1]) <= 8 && INTVAL (operands[2]) <= 7"
+ "*
+{
+ int len = INTVAL (operands[1]);
+ int bit = INTVAL (operands[2]);
+ int mask = 0;
+ rtx xoperands[2];
+
+ while (len > 0)
+ {
+ mask |= (1 << bit);
+ bit++;
+ len--;
+ }
+
+ xoperands[0] = operands[0];
+ xoperands[1] = GEN_INT (mask);
+ if (GET_CODE (operands[0]) == REG)
+ output_asm_insn (\"btst %1,%0\", xoperands);
+ else
+ output_asm_insn (\"btst %1,%A0\", xoperands);
+ return \"\";
+}"
+ [(set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+ [(set (cc0) (and:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "const_int_operand" "")))]
+ ""
+ "btst %1,%0"
+ [(set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+ [(set (cc0)
+ (and:SI
+ (subreg:SI (match_operand:QI 0 "general_operand" "R,d") 0)
+ (match_operand:SI 1 "const_int_operand" "")))]
+ ""
+ "@
+ btst %1,%A0
+ btst %1,%0"
+ [(set_attr "cc" "set_zn_c0")])
+
+;; -----------------------------------------------------------------
;; -----------------------------------------------------------------
;; Scc INSTRUCTIONS
;; -----------------------------------------------------------------
@@ -602,7 +843,7 @@
""
"@
extb %0
- mov %1,%0"
+ mov %1,%0\;extb %0"
[(set_attr "cc" "none_0hit")])
(define_insn "extendhisi2"
@@ -612,9 +853,8 @@
""
"@
exth %0
- mov %1,%0"
+ mov %1,%0\;exth %0"
[(set_attr "cc" "none_0hit")])
-
;; ----------------------------------------------------------------------
;; SHIFTS
@@ -694,6 +934,12 @@
"movm [d2,d3,a2,a3],(sp)"
[(set_attr "cc" "clobber")])
+(define_insn "return"
+ [(return)]
+ "can_use_return_insn ()"
+ "rets"
+ [(set_attr "cc" "clobber")])
+
;; Try to combine consecutive updates of the stack pointer (or any
;; other register for that matter).
(define_peephole
@@ -710,3 +956,48 @@
return \"add %1,%0\";
}"
[(set_attr "cc" "clobber")])
+
+;;
+;; We had patterns to check eq/ne, but the they don't work because
+;; 0x80000000 + 0x80000000 = 0x0 with a carry out.
+;;
+;; The Z flag and C flag would be set, and we have no way to
+;; check for the Z flag set and C flag clear.
+;;
+;; This will work on the mn10200 because we can check the ZX flag
+;; if the comparison is in HImode.
+(define_peephole
+ [(set (cc0) (match_operand:SI 0 "register_operand" "d"))
+ (set (pc) (if_then_else (ge (cc0) (const_int 0))
+ (match_operand 1 "" "")
+ (pc)))]
+ "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
+ "add %0,%0\;bcc %1"
+ [(set_attr "cc" "clobber")])
+
+(define_peephole
+ [(set (cc0) (match_operand:SI 0 "register_operand" "d"))
+ (set (pc) (if_then_else (lt (cc0) (const_int 0))
+ (match_operand 1 "" "")
+ (pc)))]
+ "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
+ "add %0,%0\;bcs %1"
+ [(set_attr "cc" "clobber")])
+
+(define_peephole
+ [(set (cc0) (match_operand:SI 0 "register_operand" "d"))
+ (set (pc) (if_then_else (ge (cc0) (const_int 0))
+ (pc)
+ (match_operand 1 "" "")))]
+ "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
+ "add %0,%0\;bcs %1"
+ [(set_attr "cc" "clobber")])
+
+(define_peephole
+ [(set (cc0) (match_operand:SI 0 "register_operand" "d"))
+ (set (pc) (if_then_else (lt (cc0) (const_int 0))
+ (pc)
+ (match_operand 1 "" "")))]
+ "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
+ "add %0,%0\;bcc %1"
+ [(set_attr "cc" "clobber")])