From 6ce1939858d6c0e1c1045caac520fe65f3065ba1 Mon Sep 17 00:00:00 2001 From: law Date: Fri, 14 Mar 1997 17:32:36 +0000 Subject: [PATCH] * mn10300/mn10300.c (const_costs): Remove unused function. * mn10300/mn10300.h (CONST_COSTS): Rework to generate better code. * mn10300/mn10300.c (print_operand): Handle 'H' and 'L' output modifers for high/low part of a 64bit value. * mn10300/mn10300.h (CONST_DOUBLE_OK_FOR_LETTER_P): Handle 'G' (LEGITIMATE_CONSTANT_P): Allow any constant. * mn10300/mn10300.md (movdi, movdf): Implement. (adddi3, subdi3): New expanders and patterns. * mn10300/mn10300.c (print_operand): Handle 'A' modifier for an address which can't be simple register indirect. * mn10300/mn10300.h (EXTRA_CONSTRAINT): Handle 'R' for bit ops. * mn10300/mn10300.md: Add several patterns to test, set and clear bitfields. * mn10300/mn10300.c (can_use_return_insn): New function. (expand_epilogue): Emit a RETURN insn if possible. * mn10300/mn10300.md (return): New pattern. * mn10300/mn10300.h (CONST_OK_FOR_LETTER_P): Handle 'N'. * mn10300/mn10300.md (andsi3): Catch "and 255,dn" and "and 65535,dn" which were not turned into zero_extend patterns. * mn10300/mn10300.h (GO_IF_LEGITIMATE_ADDRESS): Handle symbolic constant as an index/base too. * mn10300/mn10300.md (movsi): Allow SP to be loaded/saved with reg+d8 addresses. * mn10300/mn10300.md (cmpsi): Allow second operand to be a constant. (subsi3): Likewise. * mn10300/mn10300.md (sign extension patterns): Fix thinko when extending from memory. * mn10300/mn10300.md (tst peepholes): Add peepholes for test/branch based on N bit being set/clear and the data value being tested dies. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@13701 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/config/mn10300/mn10300.c | 182 +++++++++++++++++++---- gcc/config/mn10300/mn10300.h | 59 ++++++-- gcc/config/mn10300/mn10300.md | 331 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 518 insertions(+), 54 deletions(-) diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 13a9774567d..027a8e7a02f 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 2a49eb1f680..1cac33a1258 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 3089e8a2a3e..bdc65c82a4d 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")]) -- 2.11.4.GIT