OSDN Git Service

* config/bfin/bfin.md (eh_return): Call emit_jump_insn instead of
[pf3gnuchains/gcc-fork.git] / gcc / config / bfin / bfin.md
index b2b7cff..425f995 100644 (file)
 ;     e  (a0, a1)
 ;     b  (i0..i3)
 ;     f  (m0..m3)
-;     B
-;     c (i0..i3,m0..m3) CIRCREGS
-;     C (CC)            CCREGS
+;     v  (b0..b3)
+;     c  (i0..i3,m0..m3) CIRCREGS
+;     C  (CC)            CCREGS
+;     t  (lt0,lt1)
+;     k  (lc0,lc1)
+;     u  (lb0,lb1)
 ;
 
 ;; Define constants for hard registers.
    (REG_SEQSTAT 41)
    (REG_USP 42)
 
-   (REG_ARGP 43)])
+   (REG_ARGP 43)
+
+   (REG_LT0 44)
+   (REG_LT1 45)
+   (REG_LC0 46)
+   (REG_LC1 47)
+   (REG_LB0 48)
+   (REG_LB1 49)])
 
 ;; Constants used in UNSPECs and UNSPEC_VOLATILEs.
 
    (UNSPEC_MUL_WITH_FLAG 6)
    (UNSPEC_MAC_WITH_FLAG 7)
    (UNSPEC_MOVE_FDPIC 8)
-   (UNSPEC_FUNCDESC_GOT17M4 9)])
+   (UNSPEC_FUNCDESC_GOT17M4 9)
+   (UNSPEC_LSETUP_END 10)])
 
 (define_constants
   [(UNSPEC_VOLATILE_EH_RETURN 0)
 
        (const_int 2)))
 
+
+;; Classify the insns into those that are one instruction and those that
+;; are more than one in sequence.
+(define_attr "seq_insns" "single,multi"
+  (const_string "single"))
+
 ;; Conditional moves
 
 (define_expand "movsicc"
     if cc %0 =%2; /* movsicc-1b */
     if !cc %0 =%1; if cc %0=%2; /* movsicc-1 */"
   [(set_attr "length" "2,2,4")
-   (set_attr "type" "move")])
+   (set_attr "type" "move")
+   (set_attr "seq_insns" "*,*,multi")])
 
 (define_insn "*movsicc_insn2"
   [(set (match_operand:SI 0 "register_operand" "=da,da,da")
    if cc %0 =%1; /* movsicc-2a */
    if cc %0 =%1; if !cc %0=%2; /* movsicc-1 */"
   [(set_attr "length" "2,2,4")
-   (set_attr "type" "move")])
+   (set_attr "type" "move")
+   (set_attr "seq_insns" "*,*,multi")])
 
 ;; Insns to load HIGH and LO_SUM
 
    %0 = CC;
    R0 = R0 | R0; CC = AC0;"
   [(set_attr "type" "move,mvi,mcld,mcst,compare,compare,alu0")
-   (set_attr "length" "2,2,*,*,2,2,4")])
+   (set_attr "length" "2,2,*,*,2,2,4")
+   (set_attr "seq_insns" "*,*,*,*,*,*,multi")])
 
 (define_insn "movpdi"
   [(set (match_operand:PDI 0 "nonimmediate_operand" "=e,<,e")
    %0 = %1;
    %0 = %x1; %0 = %w1;
    %w0 = %1; %x0 = %1;"
-  [(set_attr "type" "move,mcst,mcld")])
+  [(set_attr "type" "move,mcst,mcld")
+   (set_attr "seq_insns" "*,multi,multi")])
 
 (define_insn "load_accumulator"
   [(set (match_operand:PDI 0 "register_operand" "=e")
 ;; The first alternative is used to make reload choose a limited register
 ;; class when faced with a movsi_insn that had its input operand replaced
 ;; with a PLUS.  We generally require fewer secondary reloads this way.
-(define_insn "*movsi_insn"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=da,x*y,da,x,x,x,da,mr")
-        (match_operand:SI 1 "general_operand" "da,x*y,xKs7,xKsh,xKuh,ix,mr,da"))]
 
+(define_insn "*movsi_insn"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=da,x*y,*k,da,da,x,x,x,da,mr")
+       (match_operand:SI 1 "general_operand" "da,x*y,da,*k,xKs7,xKsh,xKuh,ix,mr,da"))]
   "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
-  "@
+ "@
+   %0 = %1;
+   %0 = %1;
    %0 = %1;
    %0 = %1;
    %0 = %1 (X);
    #
    %0 = %1;
    %0 = %1;"
-  [(set_attr "type" "move,move,mvi,mvi,mvi,*,mcld,mcst")
-   (set_attr "length" "2,2,2,4,4,*,*,*")])
+  [(set_attr "type" "move,move,move,move,mvi,mvi,mvi,*,mcld,mcst")
+   (set_attr "length" "2,2,2,2,2,4,4,*,*,*")])
 
 (define_insn_and_split "*movv2hi_insn"
   [(set (match_operand:V2HI 0 "nonimmediate_operand" "=da,da,d,dm")
                        (match_operand:DI 2 "register_operand" "d")))]
   ""
   "%0 = %1 <op> %2;\\n\\t%H0 = %H1 <op> %H2;"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*<optab>di_zesidi_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
                        (match_operand:DI 1 "register_operand" "d")))]
   ""
   "%0 = %1 <op>  %2;\\n\\t%H0 = <high_result>;"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*<optab>di_sesdi_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (match_scratch:SI 3 "=&d"))]
   ""
   "%0 = %1 <op> %2;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %H1 <op> %3;"
-  [(set_attr "length" "8")])
+  [(set_attr "length" "8")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "negdi2"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (reg:CC REG_CC))]
   ""
   "%2 = 0; %2 = %2 - %1; cc = ac0; cc = !cc; %2 = cc;\\n\\t%0 = -%1; %H0 = -%H1; %H0 = %H0 - %2;"
-  [(set_attr "length" "16")])
+  [(set_attr "length" "16")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "one_cmpldi2"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (not:DI (match_operand:DI 1 "register_operand" "d")))]
   ""
   "%0 = ~%1;\\n\\t%H0 = ~%H1;"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 ;; DImode zero and sign extend patterns
 
         (zero_extend:DI (match_operand:QI 1 "register_operand" "d")))]
   ""
   "%0 = %T1 (Z);\\n\\t%H0 = 0;"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "zero_extendhidi2"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (zero_extend:DI (match_operand:HI 1 "register_operand" "d")))]
   ""
   "%0 = %h1 (Z);\\n\\t%H0 = 0;"
-  [(set_attr "length" "4")])
+  [(set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn_and_split "extendsidi2"
   [(set (match_operand:DI 0 "register_operand" "=d")
    %0 += %2; cc = ac0; %3 = cc; %H0 = %H0 + %3;
    %0 = %0 + %2; cc = ac0; %3 = cc; %H0 = %H0 + %H2; %H0 = %H0 + %3;"
   [(set_attr "type" "alu0")
-   (set_attr "length" "10,8,10")])
+   (set_attr "length" "10,8,10")
+   (set_attr "seq_insns" "multi,multi,multi")])
 
 (define_insn "subdi3"
   [(set (match_operand:DI 0 "register_operand" "=&d")
    (clobber (reg:CC 34))]
   ""
   "%0 = %1-%2;\\n\\tcc = ac0;\\n\\t%H0 = %H1-%H2;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
-  [(set_attr "length" "10")])
+  [(set_attr "length" "10")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*subdi_di_zesidi"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (reg:CC 34))]
   ""
   "%0 = %1 - %2;\\n\\tcc = ac0;\\n\\tcc = ! cc;\\n\\t%3 = cc;\\n\\t%H0 = %H1 - %3;"
-  [(set_attr "length" "10")])
+  [(set_attr "length" "10")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*subdi_zesidi_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (reg:CC 34))]
   ""
   "%0 = %2 - %1;\\n\\tcc = ac0;\\n\\tcc = ! cc;\\n\\t%3 = cc;\\n\\t%3 = -%3;\\n\\t%H0 = %3 - %H1"
-  [(set_attr "length" "12")])
+  [(set_attr "length" "12")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*subdi_di_sesidi"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (reg:CC 34))]
   ""
   "%0 = %1 - %2;\\n\\tcc = ac0;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %H1 - %3;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
-  [(set_attr "length" "14")])
+  [(set_attr "length" "14")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "*subdi_sesidi_di"
   [(set (match_operand:DI 0 "register_operand" "=d")
    (clobber (reg:CC 34))]
   ""
   "%0 = %2 - %1;\\n\\tcc = ac0;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %3 - %H1;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
-  [(set_attr "length" "14")])
+  [(set_attr "length" "14")
+   (set_attr "seq_insns" "multi")])
 
 ;; Combined shift/add instructions
 
   "%0 = %1 + %2 (S);"
   [(set_attr "type" "dsp32")])
 
-(define_expand "subsi3"
-  [(set (match_operand:SI 0 "register_operand" "")
-       (minus:SI (match_operand:SI 1 "register_operand" "")
-                 (match_operand:SI 2 "reg_or_7bit_operand" "")))]
-  ""
-  "")
-
-(define_insn ""
+(define_insn "subsi3"
   [(set (match_operand:SI 0 "register_operand" "=da,d,a")
        (minus:SI (match_operand:SI 1 "register_operand" "0,d,0")
-                 (match_operand:SI 2 "reg_or_7bit_operand" "Ks7,d,a")))]
-  "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -64"
+                 (match_operand:SI 2 "reg_or_neg7bit_operand" "KN7,d,a")))]
+  ""
 {
   static const char *const strings_subsi3[] = {
     "%0 += -%2;",
   "jump (%0);"
   [(set_attr "type" "misc")])
 
+;;  Hardware loop
+
+; operand 0 is the loop count pseudo register
+; operand 1 is the number of loop iterations or 0 if it is unknown
+; operand 2 is the maximum number of loop iterations
+; operand 3 is the number of levels of enclosed loops
+; operand 4 is the label to jump to at the top of the loop
+(define_expand "doloop_end"
+  [(parallel [(set (pc) (if_then_else
+                         (ne (match_operand:SI 0 "" "")
+                             (const_int 1))
+                         (label_ref (match_operand 4 "" ""))
+                         (pc)))
+             (set (match_dup 0)
+                  (plus:SI (match_dup 0)
+                           (const_int -1)))
+             (unspec [(const_int 0)] UNSPEC_LSETUP_END)
+             (clobber (match_scratch:SI 5 ""))])]
+  ""
+  {bfin_hardware_loop ();})
+
+(define_insn "loop_end"
+  [(set (pc)
+       (if_then_else (ne (match_operand:SI 0 "nonimmediate_operand" "+a*d,*b*v*f,m")
+                         (const_int 1))
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (set (match_dup 0)
+       (plus (match_dup 0)
+             (const_int -1)))
+   (unspec [(const_int 0)] UNSPEC_LSETUP_END)
+   (clobber (match_scratch:SI 2 "=X,&r,&r"))]
+  ""
+  "@
+   /* loop end %0 %l1 */
+   #
+   #"
+  [(set_attr "length" "6,10,14")])
+
+(define_split
+  [(set (pc)
+       (if_then_else (ne (match_operand:SI 0 "nondp_reg_or_memory_operand" "")
+                         (const_int 1))
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (set (match_dup 0)
+       (plus (match_dup 0)
+             (const_int -1)))
+   (unspec [(const_int 0)] UNSPEC_LSETUP_END)
+   (clobber (match_scratch:SI 2 "=&r"))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 0))
+   (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))
+   (set (match_dup 0) (match_dup 2))
+   (set (reg:BI REG_CC) (eq:BI (match_dup 2) (const_int 0)))
+   (set (pc)
+       (if_then_else (eq (reg:BI REG_CC)
+                         (const_int 0))
+                     (label_ref (match_dup 1))
+                     (pc)))]
+  "")
+
+(define_insn "lsetup_with_autoinit"
+  [(set (match_operand:SI 0 "lt_register_operand" "=t")
+       (label_ref (match_operand 1 "" "")))
+   (set (match_operand:SI 2 "lb_register_operand" "=u")
+       (label_ref (match_operand 3 "" "")))
+   (set (match_operand:SI 4 "lc_register_operand" "=k")
+       (match_operand:SI 5 "register_operand" "a"))]
+  ""
+  "LSETUP (%1, %3) %4 = %5;"
+  [(set_attr "length" "4")])
+
+(define_insn "lsetup_without_autoinit"
+  [(set (match_operand:SI 0 "lt_register_operand" "=t")
+       (label_ref (match_operand 1 "" "")))
+   (set (match_operand:SI 2 "lb_register_operand" "=u")
+       (label_ref (match_operand 3 "" "")))
+   (use (match_operand:SI 4 "lc_register_operand" "k"))]
+  ""
+  "LSETUP (%1, %3) %4;"
+  [(set_attr "length" "4")])
+
 ;;  Call instructions..
 
 ;; The explicit MEM inside the UNSPEC prevents the compiler from moving
    (set (mem:BLK (match_dup 3))
        (mem:BLK (match_dup 4)))
    (use (match_dup 2))
-   (clobber (match_scratch:HI 5 "=&d"))]
+   (clobber (match_scratch:HI 5 "=&d"))
+   (clobber (reg:SI REG_LT1))
+   (clobber (reg:SI REG_LC1))
+   (clobber (reg:SI REG_LB1))]
   ""
   "%5 = [%4++]; lsetup (1f, 1f) LC1 = %2; 1: MNOP || [%3++] = %5 || %5 = [%4++]; [%3++] = %5;"
   [(set_attr "type" "misc")
-   (set_attr "length" "16")])
+   (set_attr "length" "16")
+   (set_attr "seq_insns" "multi")])
 
 (define_insn "rep_movhi"
   [(set (match_operand:SI 0 "register_operand" "=&a")
    (set (mem:BLK (match_dup 3))
        (mem:BLK (match_dup 4)))
    (use (match_dup 2))
-   (clobber (match_scratch:HI 5 "=&d"))]
+   (clobber (match_scratch:HI 5 "=&d"))
+   (clobber (reg:SI REG_LT1))
+   (clobber (reg:SI REG_LC1))
+   (clobber (reg:SI REG_LB1))]
   ""
   "%h5 = W[%4++]; lsetup (1f, 1f) LC1 = %2; 1: MNOP || W [%3++] = %5 || %h5 = W [%4++]; W [%3++] = %5;"
   [(set_attr "type" "misc")
-   (set_attr "length" "16")])
+   (set_attr "length" "16")
+   (set_attr "seq_insns" "multi")])
 
 (define_expand "movmemsi"
   [(match_operand:BLK 0 "general_operand" "")
   ""
 {
   emit_move_insn (EH_RETURN_HANDLER_RTX, operands[0]);
-  emit_insn (gen_eh_return_internal ());
+  emit_jump_insn (gen_eh_return_internal ());
   emit_barrier ();
   DONE;
 })
 
 (define_insn_and_split "eh_return_internal"
-  [(unspec_volatile [(reg:SI REG_P2)] UNSPEC_VOLATILE_EH_RETURN)]
+  [(set (pc)
+       (unspec_volatile [(reg:SI REG_P2)] UNSPEC_VOLATILE_EH_RETURN))]
   ""
   "#"
   "reload_completed"
   ""
   "if !cc jump 4 (bp); excpt 3;"
   [(set_attr "type" "misc")
-   (set_attr "length" "4")])
+   (set_attr "length" "4")
+   (set_attr "seq_insns" "multi")])
 
 ;;; Vector instructions