OSDN Git Service

* rtl.def (NIL): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / config / m68hc11 / m68hc11.md
index 1d82f59..be8ffbf 100644 (file)
    (A_REGNUM        5)         ; A (high part of D)
    (B_REGNUM        6)         ; B (low part of D)
    (CC_REGNUM       7)         ; Condition code register
-   (SOFT_Z_REGNUM  11)          ; Z soft register
+   (SOFT_TMP_REGNUM 10)         ; TMP soft register
+   (SOFT_Z_REGNUM   11)         ; Z soft register
+   (SOFT_XY_REGNUM  12)         ; XY soft register
 ])
 
 ;;--------------------------------------------------------------------
 ;; avoid problems with the flow+cse register pass which are made
 ;; after Z register replacement.
 ;;
-(define_insn "tstqi_z_used"
+(define_insn_and_split "tstqi_z_used"
   [(set (cc0)
        (match_operand:QI 0 "tst_operand" "m"))
    (use (match_operand:HI 1 "hard_reg_operand" "dxy"))
-   (use (reg:HI 11))]
-  ""
-  "#")
-
-(define_split /* "tstqi_z_used" */
-  [(set (cc0)
-       (match_operand:QI 0 "tst_operand" ""))
-   (use (match_operand:HI 1 "hard_reg_operand" ""))
    (use (reg:HI SOFT_Z_REGNUM))]
+  ""
+  "#"
   "z_replacement_completed == 2"
   [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 1))
    (set (match_dup 1) (match_dup 2))
   [(set (cc0)
        (compare (match_operand:HI 0 "hard_reg_operand" "")
                 (match_operand:HI 1 "hard_reg_operand" "")))]
-  "reload_completed"
+  "TARGET_M6811
+   && reload_completed && !(Z_REG_P (operands[0]) || Z_REG_P (operands[1]))"
   [(set (match_dup 2) (match_dup 1))
    (set (cc0)
         (compare (match_dup 0) (match_dup 2)))]
   "operands[2] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);")
 
+(define_split
+  [(set (cc0)
+       (compare (match_operand:HI 0 "hard_reg_operand" "")
+                (match_operand:HI 1 "hard_reg_operand" "")))]
+  "0 && TARGET_M6812
+   && reload_completed && !(Z_REG_P (operands[0]) || Z_REG_P (operands[1]))"
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 1))
+   (set (cc0)
+        (compare (match_dup 0) (mem:HI (post_inc:HI (reg:HI SP_REGNUM)))))]
+  "")
+
 (define_expand "cmphi"
   [(set (cc0)
        (compare (match_operand:HI 0 "tst_operand" "")
   [(set (cc0)
        (compare (match_operand:HI 0 "tst_operand" 
                                "d,?xy,xyd,?xy,d,m,!u,dxy,dxy")
-                (match_operand:HI 1 "cmp_operand"
+                (match_operand:HI 1 "general_operand"
                                "i,i,!u,m,m,dxy,dxy,?*d*A,!*w")))]
   "TARGET_M6812"
   "*
       cc_status.flags |= CC_REVERSED;
       return \"cp%1\\t%0\";
     }
+  else if (SP_REG_P (operands[1]))
+    return \"sts\\t2,-sp\n\\tcp%0\\t2,sp+\";
   else if (H_REG_P (operands[1]))
-    return \"#\";
+    return \"psh%1\n\\tcp%0\\t2,sp+\";
   else
     return \"cp%0\\t%1\";
 }")
 (define_insn "cmphi_1_hc11"
   [(set (cc0)
        (compare (match_operand:HI 0 "tst_operand" 
-                               "dx,y,xyd,?xy,d,m,!u,dxy,dxy")
+                               "dx,y,xyd,?xy,d,m,m,dxy,dxy,?u*z,dxy,*z")
                 (match_operand:HI 1 "cmp_operand"
-                               "i,i,!u,m,m,dxy,dxy,?*d*A,!*w")))]
+                               "i,i,!u,m,m,?xy,d,?*d*A,?u,dxy,!*w,i")))]
   "TARGET_M6811"
   "*
 {
     return \"cp%0\\t%1\";
 }")
 
-(define_insn "cmphi_z_used"
+(define_insn_and_split "cmphi_z_used"
   [(set (cc0)
        (compare (match_operand:HI 0 "tst_operand" "dxy,m")
-                (match_operand:HI 1 "cmp_operand" "m,dxy")))
+                (match_operand:HI 1 "cmp_operand" "mi,dxy")))
    (use (match_operand:HI 2 "hard_reg_operand" "dxy,dxy"))
    (use (reg:HI SOFT_Z_REGNUM))]
   ""
-  "#")
-  
-(define_split /* "cmphi_z_used" */
-  [(set (cc0)
-       (compare (match_operand:HI 0 "tst_operand" "")
-                (match_operand:HI 1 "cmp_operand" "")))
-   (use (match_operand:HI 2 "hard_reg_operand" ""))
-   (use (reg:HI SOFT_Z_REGNUM))]
+  "#"
   "z_replacement_completed == 2"
   [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2))
    (set (match_dup 2) (match_dup 3))
    operands[3] = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
    operands[4] = gen_rtx_REG (QImode, SOFT_TMP_REGNUM);")
 
-(define_insn "bitcmpqi_z_used"
+(define_insn_and_split "bitcmpqi_z_used"
   [(set (cc0)
        (and:QI (match_operand:QI 0 "tst_operand" "d,m")
                (match_operand:QI 1 "cmp_operand" "m,d")))
    (use (match_operand:HI 2 "hard_reg_operand" "xy,xy"))
    (use (reg:HI SOFT_Z_REGNUM))]
   ""
-  "#")
-  
-(define_split /* "bitcmpqi_z_used" */
-  [(set (cc0)
-       (and:QI (match_operand:QI 0 "tst_operand" "")
-               (match_operand:QI 1 "cmp_operand" "")))
-   (use (match_operand:HI 2 "hard_reg_operand" ""))
-   (use (reg:HI SOFT_Z_REGNUM))]
+  "#"
   "z_replacement_completed == 2"
   [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2))
    (set (match_dup 2) (match_dup 3))
    return \"cmpb\\t%b0\";
 }")
 
-(define_insn "cmpqi_z_used"
+(define_insn_and_split "cmpqi_z_used"
   [(set (cc0)
        (compare (match_operand:QI 0 "tst_operand" "dxy,m")
                 (match_operand:QI 1 "cmp_operand" "m,dxy")))
    (use (match_operand:HI 2 "hard_reg_operand" "dxy,dxy"))
    (use (reg:HI SOFT_Z_REGNUM))]
   ""
-  "#")
-  
-(define_split /* cmpqi_z_used */
-  [(set (cc0)
-       (compare (match_operand:QI 0 "tst_operand" "")
-                (match_operand:QI 1 "cmp_operand" "")))
-   (use (match_operand:HI 2 "hard_reg_operand" ""))
-   (use (reg:HI SOFT_Z_REGNUM))]
+  "#"
   "z_replacement_completed == 2"
   [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2))
    (set (match_dup 2) (match_dup 3))
 ;; (strict_low_part ...) information.  This is correct for our machine
 ;; description but not for GCC optimization passes.
 ;;
-(define_insn "movstrictsi"
+(define_insn_and_split "movstrictsi"
   [(set (strict_low_part (match_operand:SI 0 "non_push_operand" "+um,D,D"))
        (match_operand:SI 1 "general_operand" "D,Dim,uD"))]
   ""
-  "#")
-
-(define_split
-  [(set (strict_low_part (match_operand:SI 0 "non_push_operand" ""))
-       (match_operand:SI 1 "general_operand" ""))]
+  "#"
   "z_replacement_completed == 2"
   [(set (match_dup 0) (match_dup 1))]
   "")
 
-(define_insn "movstricthi"
+(define_insn_and_split "movstricthi"
   [(set (strict_low_part (match_operand:HI 0 "non_push_operand" "+um,dA,dA"))
        (match_operand:HI 1 "general_operand" "dA,dAim,u"))]
   ""
-  "#")
-
-(define_split
-  [(set (strict_low_part (match_operand:HI 0 "non_push_operand" ""))
-       (match_operand:HI 1 "general_operand" ""))]
+  "#"
   "z_replacement_completed == 2"
   [(set (match_dup 0) (match_dup 1))]
   "")
 
-(define_insn "movstrictqi"
+(define_insn_and_split "movstrictqi"
   [(set (strict_low_part (match_operand:QI 0 "non_push_operand" "+mu,!dA"))
        (match_operand:QI 1 "general_operand" "d,imudA"))]
   ""
-  "#")
-
-(define_split
-  [(set (strict_low_part (match_operand:QI 0 "non_push_operand" ""))
-       (match_operand:QI 1 "general_operand" ""))]
+  "#"
   "z_replacement_completed == 2"
   [(set (match_dup 0) (match_dup 1))]
   "")
     }
 ")
 
-(define_insn "movdi_internal"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=ou,U,!u,U,m,m,!u")
+;; Separate push from normal moves to avoid reloading problems
+;; The 'clr' is not able to push on 68HC11 so we really need a scratch.
+;; We can also accept more scratch registers.
+(define_insn_and_split "*pushdi_internal"
+  [(set (match_operand:DI 0 "push_operand" "=<,<,<,<")
+       (match_operand:DI 1 "general_operand" "i,U,m,!u"))
+   (clobber (match_scratch:HI 2 "=&dA,&d,&d,&dA"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_move (operands[0], operands[1], operands[2]);
+   DONE;")
+
+(define_insn_and_split "movdi_internal"
+  [(set (match_operand:DI 0 "non_push_operand" "=m!u,U,!u,U,m,m,!u")
        (match_operand:DI 1 "general_operand" "K,iU,iU,!u,mi,!u,!mu"))
    (clobber (match_scratch:HI 2 "=X,&d,&d,&d,&d,&d,&d"))]
   ""
-  "#")
-
-(define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (match_operand:DI 1 "general_operand" ""))
-   (clobber (match_scratch:HI 2 ""))]
+  "#"
   "reload_completed"
   [(const_int 0)]
   "m68hc11_split_move (operands[0], operands[1], operands[2]);
     }
 ")
 
-(define_insn "movdf_internal"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=ou,U,!u,U,m,m,!u")
+;; See pushdi_internal
+(define_insn_and_split "*pushdf_internal"
+  [(set (match_operand:DF 0 "push_operand" "=<,<,<,<")
+       (match_operand:DF 1 "general_operand" "i,U,m,!u"))
+   (clobber (match_scratch:HI 2 "=&dA,&d,&d,&dA"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_move (operands[0], operands[1], operands[2]);
+   DONE;")
+
+(define_insn_and_split "movdf_internal"
+  [(set (match_operand:DF 0 "non_push_operand" "=mu,U,!u,U,m,m,!u")
        (match_operand:DF 1 "general_operand" "G,iU,iU,!u,mi,!u,!mu"))
    (clobber (match_scratch:HI 2 "=X,&d,&d,&d,&d,&d,&d"))]
   ""
-  "#")
-
-(define_split
-  [(set (match_operand:DF 0 "nonimmediate_operand" "")
-       (match_operand:DF 1 "general_operand" ""))
-   (clobber (match_scratch:HI 2 ""))]
+  "#"
   "reload_completed"
   [(const_int 0)]
   "m68hc11_split_move (operands[0], operands[1], operands[2]);
     }
 ")
 
-(define_insn "movsi_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=ou,mu,?D,m,?D,?u,?u,!u,D")
-       (match_operand:SI 1 "general_operand"      "K,imu,im,?D,!u,?D,mi,!u,!D"))
-   (clobber (match_scratch:HI 2                    "=X,&d,X,X,X,X,&d,&d,X"))]
+(define_insn_and_split "*pushsi_internal"
+  [(set (match_operand:SI 0 "push_operand" "=<,<,<,<,<")
+       (match_operand:SI 1 "general_operand" "!D,i,U,m,!u"))
+   (clobber (match_scratch:HI 2 "=X,&dA,&d,&d,&dA"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_move (operands[0], operands[1], operands[2]);
+   DONE;")
 
-(define_split
-  [(set (match_operand:SI 0 "nonimmediate_operand" "")
-       (match_operand:SI 1 "general_operand" ""))
-   (clobber (match_scratch:HI 2 ""))]
+(define_insn_and_split "movsi_internal"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=mu,mu,?D,m,?D,?u,?u,!u,D")
+       (match_operand:SI 1 "general_operand" "K,imu,im,?D,!u,?D,mi,!u,!D"))
+   (clobber (match_scratch:HI 2               "=X,&d,X,X,X,X,&d,&d,X"))]
+  ""
+  "#"
   "reload_completed"
   [(const_int 0)]
   "m68hc11_split_move (operands[0], operands[1], operands[2]);
     }
 ")
 
-(define_insn "movsf_internal"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=o!u,m,D,m,D,!u,!u,!u,D")
+(define_insn_and_split "*pushsf_internal"
+  [(set (match_operand:SF 0 "push_operand" "=<,<,<,<,<")
+       (match_operand:SF 1 "general_operand" "!D,i,U,m,!u"))
+   (clobber (match_scratch:HI 2 "=X,&dA,&d,&d,&dA"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_move (operands[0], operands[1], operands[2]);
+   DONE;")
+
+(define_insn_and_split "movsf_internal"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m!u,m,D,m,D,!u,!u,!u,D")
        (match_operand:SF 1 "general_operand" "G,im,im,D,!u,D,mi,!u,!D"))
    (clobber (match_scratch:HI 2 "=X,&d,X,X,X,X,&d,&d,X"))]
   ""
-  "#")
-
-(define_split
-  [(set (match_operand:SF 0 "nonimmediate_operand" "")
-       (match_operand:SF 1 "general_operand" ""))
-   (clobber (match_scratch:HI 2 ""))]
+  "#"
   "reload_completed"
   [(const_int 0)]
   "m68hc11_split_move (operands[0], operands[1], operands[2]);
 }")
 
 (define_insn "movhi_const0"
-  [(set (match_operand:HI 0 "non_push_operand" "=d,A,um")
+  [(set (match_operand:HI 0 "splitable_operand" "=d,A,um")
        (const_int 0))]
   ""
   "@
    clr\\t%b0\\n\\tclr\\t%h0")
 
 (define_insn "*movhi_68hc12"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=U,dAw,U,U,m,!u")
-       (match_operand:HI 1 "general_operand" "U,rim,dAwi,!u,dAw,riU"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=U,dAw,dAw,U,U,m,!u")
+       (match_operand:HI 1 "general_operand" "U,dAwim,!u,dAwi,!u,dAw,riU"))]
   "TARGET_M6812"
   "*
 {
 (define_split
   [(set (match_operand:QI 0 "hard_addr_reg_operand" "")
         (match_operand:QI 1 "general_operand" ""))]
-  "z_replacement_completed == 2 && GET_MODE (operands[0]) == QImode
+  "z_replacement_completed == 2
    && !reg_mentioned_p (operands[0], operands[1])
-   && !D_REG_P (operands[1])"
+   && !(D_REG_P (operands[1]) || Q_REG_P (operands[1]))"
   [(parallel [(set (reg:HI D_REGNUM) (match_dup 2))
               (set (match_dup 2) (reg:HI D_REGNUM))])
    (set (reg:QI D_REGNUM) (match_dup 1))
 (define_split
   [(set (match_operand:QI 0 "nonimmediate_operand" "")
         (match_operand:QI 1 "hard_addr_reg_operand" ""))]
-  "z_replacement_completed == 2 && GET_MODE (operands[1]) == QImode
+  "z_replacement_completed == 2
    && !reg_mentioned_p (operands[1], operands[0])
-   && !D_REG_P (operands[0])"
+   && !(D_REG_P (operands[0]) || Q_REG_P (operands[0]))"
   [(parallel [(set (reg:HI D_REGNUM) (match_dup 2))
               (set (match_dup 2) (reg:HI D_REGNUM))])
    (set (match_dup 0) (reg:QI D_REGNUM))
   [(set (match_operand:DI 0 "nonimmediate_operand" "=m,m,!u,!u")
        (zero_extend:DI 
            (match_operand:SI 1 "nonimmediate_operand" "m,Du,m,Du")))
-   (clobber (match_scratch:HI 2 "=d,d,d,d"))]
+   (clobber (match_scratch:HI 2 "=d,d,&d,d"))]
   ""
   "#")
 
 }")
 
 (define_insn "*addhi3_68hc12"
-  [(set (match_operand:HI 0 "register_operand" "=xyd,d,xy*z*w,xy*z*w,xy*z")
-        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,xy*zw,0")
+  [(set (match_operand:HI 0 "register_operand" "=d*A,d,xy*A*w,xy*A*w,xy*A")
+        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,xy*Aw,0")
                  (match_operand:HI 2 "general_operand" "i,m*A*wu,id,id,!mu*A")))]
   "TARGET_M6812"
   "*
 }")
 
 (define_insn "*addhi3"
-  [(set (match_operand:HI 0 "hard_reg_operand" "=A,dA,d,!A,d*A,!d*A")
-       (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0,0,0")
-                (match_operand:HI 2 "general_operand" "N,I,i,I,mi*A*d,!u*d*w")))]
+  [(set (match_operand:HI 0 "hard_reg_operand" "=A,dA,d,!A,d*A,d,!d*A")
+       (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0,0,0,0")
+                (match_operand:HI 2 "general_operand" "N,I,i,I,mi*A*d,*u,!u*d*w")))]
   "TARGET_M6811"
   "*
 {
 
 
 (define_insn "*subhi3"
-  [(set (match_operand:HI 0 "register_operand" "=d,*A,d*A")
-       (minus:HI (match_operand:HI 1 "register_operand" "0,0,0")
-                 (match_operand:HI 2 "general_operand" "im*A*d,im*d*A,!u")))]
+  [(set (match_operand:HI 0 "register_operand" "=d,*A,d,*A")
+       (minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0")
+                 (match_operand:HI 2 "general_operand" "im*A*d,im*d*A,u,!u")))]
   ""
   "*
 {
 ;;- and instructions.
 ;;--------------------------------------------------------------------
 
-(define_insn "anddi3"
+(define_insn_and_split "anddi3"
   [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u")
        (and:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu")
                (match_operand:DI 2 "general_operand" "imu,imu")))
    (clobber (match_scratch:HI 3 "=d,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (SImode, AND, operands);
+   DONE;")
 
-(define_insn "andsi3"
+(define_insn_and_split "andsi3"
   [(set (match_operand:SI 0 "register_operand" "=D,!u")
        (and:SI (match_operand:SI 1 "register_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "Dimu,imu")))
    (clobber (match_scratch:HI 3 "=X,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (HImode, AND, operands);
+   DONE;")
 
 (define_expand "andhi3"
   [(set (match_operand:HI 0 "register_operand" "")
   "")
 
 (define_insn "*andhi3_mem"
-  [(set (match_operand:HI 0 "memory_operand" "=Q,R")
+  [(set (match_operand:HI 0 "memory_operand" "=R,Q")
        (and:HI (match_dup 0)
                (match_operand:HI 1 "immediate_operand" "i,i")))
-   (clobber (match_scratch:HI 2 "=xy,X"))]
+   (clobber (match_scratch:HI 2 "=X,xy"))]
   "TARGET_RELAX && !TARGET_M6812"
   "*
 {
   /* When destination is a global variable, generate a .relax instruction
      and load the address in the clobber register.  That load can be
      eliminated by the linker if the address is in page0.  */
-  if (which_alternative == 0)
+  if (which_alternative == 1)
     {
       rtx ops[3];
 
 
 (define_insn "*andhi3_gen"
   [(set (match_operand:HI 0 "register_operand" "=d,d,!*A")
-       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
-               (match_operand:HI 2 "general_operand" "mi,!u*A,!um*A")))]
+       (and:HI (match_operand:HI 1 "splitable_operand" "%0,0,0")
+               (match_operand:HI 2 "splitable_operand" "mi,!u*A,!um*Ai")))]
   ""
   "*
 {
   "")
 
 (define_insn "*andqi3_mem"
-  [(set (match_operand:QI 0 "memory_operand" "=Q,R")
+  [(set (match_operand:QI 0 "memory_operand" "=R,Q")
        (and:QI (match_dup 0)
                (match_operand:QI 1 "const_int_operand" "i,i")))
-   (clobber (match_scratch:HI 2 "=xy,X"))]
+   (clobber (match_scratch:HI 2 "=X,xy"))]
   "TARGET_RELAX && !TARGET_M6812"
   "*
 {
   /* When destination is a global variable, generate a .relax instruction
      and load the address in the clobber register.  That load can be
      eliminated by the linker if the address is in page0.  */
-  if (which_alternative == 0)
+  if (which_alternative == 1)
     {
       rtx ops[3];
 
 ;;- Bit set or instructions.
 ;;--------------------------------------------------------------------
 
-(define_insn "iordi3"
+(define_insn_and_split "iordi3"
   [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u")
        (ior:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu")
                (match_operand:DI 2 "general_operand" "imu,imu")))
    (clobber (match_scratch:HI 3 "=d,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (SImode, IOR, operands);
+   DONE;")
 
-(define_insn "iorsi3"
+(define_insn_and_split "iorsi3"
   [(set (match_operand:SI 0 "register_operand" "=D,!u")
        (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "Dimu,imu")))
    (clobber (match_scratch:HI 3 "=X,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (HImode, IOR, operands);
+   DONE;")
 
 (define_expand "iorhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (ior:HI (match_operand:HI 1 "register_operand" "")
-               (match_operand:HI 2 "general_operand" "")))]
+               (match_operand:HI 2 "splitable_operand" "")))]
   ""
   "")
 
 (define_insn "*iorhi3_mem"
-  [(set (match_operand:HI 0 "memory_operand" "=Q,R")
+  [(set (match_operand:HI 0 "memory_operand" "=R,Q")
        (ior:HI (match_dup 0)
                (match_operand:HI 1 "const_int_operand" "")))
-   (clobber (match_scratch:HI 2 "=xy,X"))]
+   (clobber (match_scratch:HI 2 "=X,xy"))]
   "TARGET_RELAX && !TARGET_M6812"
   "*
 {
       return \"\";
     }
   CC_STATUS_INIT;
-  if (which_alternative == 0)
+  if (which_alternative == 1)
     {
       rtx ops[3];
 
 
 (define_insn "*iorhi3_gen"
   [(set (match_operand:HI 0 "register_operand" "=d,d,!*A")
-       (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0")
-               (match_operand:HI 2 "general_operand" "mi,!u*A,!um*A")))]
+       (ior:HI (match_operand:HI 1 "splitable_operand" "%0,0,0")
+               (match_operand:HI 2 "splitable_operand" "mi,!u*A,!um*Ai")))]
   ""
   "*
 {
   "")
 
 (define_insn "*iorqi3_mem"
-  [(set (match_operand:QI 0 "memory_operand" "=Q,R")
+  [(set (match_operand:QI 0 "memory_operand" "=R,Q")
        (ior:QI (match_dup 0)
                (match_operand:QI 1 "const_int_operand" "")))
-   (clobber (match_scratch:HI 2 "=xy,X"))]
+   (clobber (match_scratch:HI 2 "=X,xy"))]
   "TARGET_RELAX && !TARGET_M6812"
   "*
 {
       cc_status = cc_prev_status;
       return \"\";
     }
-  if (which_alternative == 0)
+  if (which_alternative == 1)
     {
       rtx ops[3];
 
 ;;- xor instructions.
 ;;--------------------------------------------------------------------
 
-(define_insn "xordi3"
+(define_insn_and_split "xordi3"
   [(set (match_operand:DI 0 "reg_or_some_mem_operand" "=m,u")
        (xor:DI (match_operand:DI 1 "reg_or_some_mem_operand" "%imu,imu")
                (match_operand:DI 2 "general_operand" "imu,imu")))
    (clobber (match_scratch:HI 3 "=d,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (SImode, XOR, operands);
+   DONE;")
 
-(define_insn "xorsi3"
+(define_insn_and_split "xorsi3"
   [(set (match_operand:SI 0 "register_operand" "=D,!u")
        (xor:SI (match_operand:SI 1 "register_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "Dimu,imu")))
    (clobber (match_scratch:HI 3 "=X,d"))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "m68hc11_split_logical (HImode, XOR, operands);
+   DONE;")
 
 (define_insn "xorhi3"
   [(set (match_operand:HI 0 "register_operand" "=d,d,!*A")
-       (xor:HI (match_operand:HI 1 "register_operand" "%0,0,0")
-               (match_operand:HI 2 "general_operand" "im,!u*A,!ium*A")))]
+       (xor:HI (match_operand:HI 1 "splitable_operand" "%0,0,0")
+               (match_operand:HI 2 "splitable_operand" "im,!u*A,!ium*A")))]
   ""
   "*
 {
 ;;- Bit set or instructions.
 ;;--------------------------------------------------------------------
 
-(define_insn "*logicalsi3_zexthi"
+(define_insn_and_split "*logicalsi3_zexthi"
   [(set (match_operand:SI 0 "register_operand" "=D")
        (match_operator:SI 3 "m68hc11_logical_operator"
                [(zero_extend:SI
                     (match_operand:HI 1 "general_operand" "imudA"))
                 (match_operand:SI 2 "general_operand" "Dimu")]))]
   ""
-  "#")
+  "#"
+  "reload_completed"
+  [(set (reg:HI D_REGNUM) (match_dup 4))
+   (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 5)]))
+   (set (reg:HI X_REGNUM) (match_dup 6))]
+  "PUT_MODE (operands[3], HImode);
+   if (X_REG_P (operands[2]))
+     {
+       operands[5] = operands[1];
+       /* Make all the (set (REG:x) (REG:y)) a nop set.  */
+       operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM);
+       operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM);
+     }
+   else
+     {
+       operands[4] = operands[1];
+       operands[5] = m68hc11_gen_lowpart (HImode, operands[2]);
+       operands[6] = m68hc11_gen_highpart (HImode, operands[2]);
+     }
+   /* For an AND, make sure the high 16-bit part is cleared.  */
+   if (GET_CODE (operands[3]) == AND)
+     {
+       operands[6] = const0_rtx;
+     }
+   ")
 
-(define_insn "*logicalsi3_zextqi"
+(define_insn_and_split "*logicalsi3_zextqi"
   [(set (match_operand:SI 0 "register_operand" "=D,D,D")
        (match_operator:SI 3 "m68hc11_logical_operator"
                [(zero_extend:SI
                     (match_operand:QI 1 "general_operand" "d,*A,imu"))
                 (match_operand:SI 2 "general_operand" "imu,imu,0")]))]
   ""
-  "#")
-
-(define_split /* logicalsi3_zextqi */
-  [(set (match_operand:SI 0 "register_operand" "")
-       (match_operator:SI 3 "m68hc11_logical_operator"
-                [(zero_extend:SI
-                    (match_operand:QI 1 "general_operand" ""))
-                 (match_operand:SI 2 "general_operand" "")]))]
+  "#"
   "z_replacement_completed == 2"
   [(set (reg:QI A_REGNUM) (match_dup 4))
    (set (reg:QI D_REGNUM) (match_dup 7))
      }
    ")
 
-(define_split /* logicalsi3_zexthi */
-  [(set (match_operand:SI 0 "register_operand" "")
-       (match_operator:SI 3 "m68hc11_logical_operator"
-                [(zero_extend:SI
-                    (match_operand:HI 1 "general_operand" ""))
-                 (match_operand:SI 2 "general_operand" "")]))]
-  "reload_completed"
-  [(set (reg:HI D_REGNUM) (match_dup 4))
-   (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 5)]))
-   (set (reg:HI X_REGNUM) (match_dup 6))]
-  "PUT_MODE (operands[3], HImode);
-   if (X_REG_P (operands[2]))
-     {
-       operands[5] = operands[1];
-       /* Make all the (set (REG:x) (REG:y)) a nop set.  */
-       operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM);
-       operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM);
-     }
-   else
-     {
-       operands[4] = operands[1];
-       operands[5] = m68hc11_gen_lowpart (HImode, operands[2]);
-       operands[6] = m68hc11_gen_highpart (HImode, operands[2]);
-     }
-   /* For an AND, make sure the high 16-bit part is cleared.  */
-   if (GET_CODE (operands[3]) == AND)
-     {
-       operands[6] = const0_rtx;
-     }
-   ")
-
-(define_insn "*logicalhi3_zexthi_ashift8"
+(define_insn_and_split "*logicalhi3_zexthi_ashift8"
   [(set (match_operand:HI 0 "register_operand" "=d")
        (match_operator:HI 3 "m68hc11_logical_operator"
                [(zero_extend:HI
-                    (match_operand:QI 1 "general_operand" "imud"))
+                    (match_operand:QI 1 "general_operand" "imud*A"))
                 (ashift:HI
-                    (match_operand:HI 2 "general_operand" "dimu")
+                    (match_operand:HI 2 "general_operand" "imud*A")
                     (const_int 8))]))]
   ""
-  "#")
+  "#"
+  "z_replacement_completed == 2"
+  [(set (reg:QI A_REGNUM) (match_dup 4))
+   (set (reg:QI B_REGNUM) (match_dup 5))]
+  "
+   if (GET_CODE (operands[3]) == AND)
+     {
+       emit_insn (gen_movhi (operands[0], const0_rtx));
+       DONE;
+     }
+   else
+     {
+       operands[5] = operands[1];
+       if (D_REG_P (operands[2]))
+         {
+           operands[4] = gen_rtx_REG (QImode, HARD_B_REGNUM);
+         }
+       else
+         {
+           operands[4] = m68hc11_gen_lowpart (QImode, operands[2]);
+         }
+     }
+  ")
 
-(define_insn "*logicalhi3_zexthi"
+(define_insn_and_split "*logicalhi3_zexthi"
   [(set (match_operand:HI 0 "register_operand" "=d,d")
        (match_operator:HI 3 "m68hc11_logical_operator"
                [(zero_extend:HI
                     (match_operand:QI 1 "general_operand" "imd*A,?u"))
                 (match_operand:HI 2 "general_operand" "dim,?dimu")]))]
   ""
-  "#")
-
-(define_split /* logicalhi3_zexthi */
-  [(set (match_operand:HI 0 "register_operand" "")
-       (match_operator:HI 3 "m68hc11_logical_operator"
-               [(zero_extend:HI
-                    (match_operand:QI 1 "general_operand" ""))
-                (match_operand:HI 2 "general_operand" "")]))]
+  "#"
   "z_replacement_completed == 2"
   [(set (reg:QI B_REGNUM) (match_dup 6))
    (set (reg:QI A_REGNUM) (match_dup 4))
      }
   ")
 
-(define_split /* logicalhi3_zexthi_ashift8 */
-  [(set (match_operand:HI 0 "register_operand" "")
-       (match_operator:HI 3 "m68hc11_logical_operator"
-               [(zero_extend:HI
-                    (match_operand:QI 1 "general_operand" ""))
-                (ashift:HI
-                    (match_operand:HI 2 "general_operand" "")
-                    (const_int 8))]))]
-  "z_replacement_completed == 2"
-  [(set (reg:QI A_REGNUM) (match_dup 4))
-   (set (reg:QI B_REGNUM) (match_dup 5))]
-  "
-   if (GET_CODE (operands[3]) == AND)
-     {
-       emit_insn (gen_movhi (operands[0], const0_rtx));
-       DONE;
-     }
-   else
-     {
-       operands[5] = operands[1];
-       if (D_REG_P (operands[2]))
-         {
-           operands[4] = gen_rtx_REG (QImode, HARD_B_REGNUM);
-         }
-       else
-         {
-           operands[4] = m68hc11_gen_lowpart (QImode, operands[2]);
-         }
-     }
-  ")
 
-(define_insn "*logicalsi3_silshr16"
-  [(set (match_operand:SI 0 "register_operand" "=D,D,D")
+(define_insn_and_split "*logicalsi3_silshr16"
+  [(set (match_operand:SI 0 "register_operand" "=D,D,D,?D")
           (match_operator:SI 3 "m68hc11_logical_operator"
              [(lshiftrt:SI 
-                  (match_operand:SI 1 "general_operand" "uim,uim,?D")
+                  (match_operand:SI 1 "general_operand" "uim,uim,0,0")
                   (const_int 16))
-               (match_operand:SI 2 "general_operand" "uim,0,0")]))]
+               (match_operand:SI 2 "general_operand" "uim,0,uim,0")]))]
   ""
-  "#")
-
-(define_split /* logicalsi3_silshr16 */
-  [(set (match_operand:SI 0 "register_operand" "")
-          (match_operator:SI 3 "m68hc11_logical_operator"
-               [(lshiftrt:SI 
-                       (match_operand:SI 1 "general_operand" "")
-                       (const_int 16))
-                (match_operand:SI 2 "general_operand" "")]))]
+  "#"
   "reload_completed"
   [(set (reg:HI D_REGNUM) (match_dup 4))
    (set (reg:HI D_REGNUM) (match_op_dup 3 [(reg:HI D_REGNUM) (match_dup 5)]))
      }
 ")
 
-(define_insn "*logicalsi3_silshl16"
+(define_insn_and_split "*logicalsi3_silshl16"
   [(set (match_operand:SI 0 "register_operand" "=D,D")
           (match_operator:SI 3 "m68hc11_logical_operator"
              [(ashift:SI 
                   (const_int 16))
                (match_operand:SI 2 "general_operand" "0,0")]))]
   ""
-  "#")
-
-(define_split /* logicalsi3_silshl16 */
-  [(set (match_operand:SI 0 "register_operand" "")
-          (match_operator:SI 3 "m68hc11_logical_operator"
-               [(ashift:SI 
-                       (match_operand:SI 1 "general_operand" "")
-                       (const_int 16))
-                (match_operand:SI 2 "general_operand" "")]))]
+  "#"
   "z_replacement_completed == 2"
   [(set (reg:HI X_REGNUM) (match_op_dup 3 [(reg:HI X_REGNUM) (match_dup 4)]))
    (set (reg:HI D_REGNUM) (match_dup 5))]
      operands[5] = gen_rtx_REG (HImode, HARD_D_REGNUM);
    ")
 
-
-;;--------------------------------------------------------------------
-;;- 64/32-bit Logical Operations.  Patterns are defined so that GCC
-;; can optimize correctly.  These insns are split by the `final'
-;; pass (# pattern).  They are split to fall in the corresponding
-;; 16-bit logical patterns.
-;;--------------------------------------------------------------------
-
-;; Split 64-bit logical operations: anddi3, iordi3, xordi3
-(define_split
-  [(set (match_operand:DI 0 "reg_or_some_mem_operand" "")
-       (match_operator:DI 4 "m68hc11_logical_operator"
-            [(match_operand:DI 1 "reg_or_some_mem_operand" "")
-             (match_operand:DI 2 "general_operand" "")]))
-   (clobber (match_scratch:HI 3 ""))]
+(define_insn_and_split "*logicalsi3_silshl16_zext"
+  [(set (match_operand:SI 0 "register_operand" "=D,D,D")
+          (match_operator:SI 3 "m68hc11_logical_operator"
+             [(ashift:SI
+                 (zero_extend:SI
+                    (match_operand:HI 1 "general_operand" "uim,udA,!dA"))
+                 (const_int 16))
+           (zero_extend:SI (match_operand:HI 2 "general_operand" "uidA,um,!dA"))]))]
+  ""
+  "#"
+  ;; Must split before z register replacement
   "reload_completed"
-  [(const_int 0)]
-  "m68hc11_split_logical (SImode, GET_CODE (operands[4]), operands);
-   DONE;")
-
-;; Split 32-bit logical operations: andsi3, iorsi3, xorsi3
-(define_split
-  [(set (match_operand:SI 0 "register_operand" "")
-       (match_operator:SI 3 "m68hc11_logical_operator"
-            [(match_operand:SI 1 "register_operand" "")
-             (match_operand:SI 2 "general_operand" "")]))]
-  "0 && reload_completed"
-  [(const_int 0)]
-  "m68hc11_split_logical (HImode, GET_CODE (operands[3]), operands);
-   DONE;")
+  [(set (match_dup 4) (match_dup 5))
+   (set (match_dup 6) (match_dup 7))]
+  "
+    /* set (X_REGNUM) (d), set (D_REGNUM) (1) */
+   if (GET_CODE (operands[1]) == HARD_D_REGNUM
+       && GET_CODE (operands[3]) != AND)
+     {
+       /* This particular case is too early to be split before
+          Z register replacement because the cse-reg pass we do
+         does not recognize the 'swap_areg'.  It is ok to handle
+         this case after.  */
+       if (z_replacement_completed != 2)
+         {
+          FAIL;
+        }
+       emit_move_insn (gen_rtx_REG (HImode, HARD_X_REGNUM), operands[2]);
+       emit_insn (gen_swap_areg (gen_rtx_REG (HImode, HARD_D_REGNUM),
+                                gen_rtx_REG (HImode, HARD_X_REGNUM)));
+     }
+   operands[4] = gen_rtx_REG (HImode, HARD_D_REGNUM);
+   operands[6] = gen_rtx_REG (HImode, HARD_X_REGNUM);
+   operands[5] = operands[2];
+   operands[7] = operands[1];
 
-;; Split 32-bit logical operations: andsi3, iorsi3, xorsi3
-(define_split
-  [(set (match_operand:SI 0 "reg_or_some_mem_operand" "")
-       (match_operator:SI 4 "m68hc11_logical_operator"
-            [(match_operand:SI 1 "reg_or_some_mem_operand" "")
-             (match_operand:SI 2 "general_operand" "")]))
-   (clobber (match_scratch:HI 3 ""))]
-  "reload_completed"
-  [(const_int 0)]
-  "m68hc11_split_logical (HImode, GET_CODE (operands[4]), operands);
-   DONE;")
+   if (GET_CODE (operands[3]) == AND)
+     operands[5] = operands[7] = const0_rtx;
+   ")
 
 ;;--------------------------------------------------------------------
 ;; 16-bit Arithmetic and logical operations on X and Y:
     }
 }")
 
-(define_insn "*ashldi3_const32"
+(define_insn_and_split "*ashldi3_const32"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=<,m,u")
        (ashift:DI (match_operand:DI 1 "general_operand" "umi,umi,umi")
                   (const_int 32)))
    (clobber (match_scratch:HI 2 "=&A,d,d"))]
    ""
-   "#")
-
-(define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (ashift:DI (match_operand:DI 1 "general_operand" "")
-                  (const_int 32)))
-   (clobber (match_scratch:HI 2 ""))]
+   "#"
    "reload_completed"
    [(const_int 0)]
    "/* Move the lowpart in the highpart first in case the shift
       {
          m68hc11_split_move (m68hc11_gen_lowpart (SImode, operands[0]),
                             const0_rtx, operands[2]);
+
+         /* Adjust first operand if it uses SP so that we take into
+            account the above push.  Can occur only for 68HC12.  */
+         if (reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM),
+                             operands[1]))
+           operands[1] = adjust_address (operands[1],
+                                        GET_MODE (operands[0]), 4);
       }
     m68hc11_split_move (m68hc11_gen_highpart (SImode, operands[0]),
                        m68hc11_gen_lowpart (SImode, operands[1]),
       }
     DONE;")
 
-(define_insn "*ashldi3_const1"
+(define_insn_and_split "*ashldi3_const1"
   [(set (match_operand:DI 0 "non_push_operand" "=m,m,u")
        (ashift:DI (match_operand:DI 1 "general_operand" "mi,u,umi")
                   (const_int 1)))
    (clobber (match_scratch:HI 2 "=d,d,d"))]
    ""
-   "#")
-
-(define_split
-  [(set (match_operand:DI 0 "non_push_operand" "")
-       (ashift:DI (match_operand:DI 1 "general_operand" "")
-                  (const_int 1)))
-   (clobber (match_scratch:HI 2 ""))]
+   "#"
    "z_replacement_completed == 2"
    [(set (match_dup 2) (match_dup 3))
     (set (match_dup 2) (ashift:HI (match_dup 2) (const_int 1)))
     operands[8] = m68hc11_gen_lowpart (HImode, operands[8]);")
 
 (define_insn "addsi_silshr16"
-  [(set (match_operand:SI 0 "register_operand" "=D,D")
-          (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "!*uim,0")
+  [(set (match_operand:SI 0 "register_operand" "=D,D,!D")
+          (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "!*uim,0,0")
                                (const_int 16))
-                  (match_operand:SI 2 "general_operand" "0,m!*u")))]
+                  (match_operand:SI 2 "general_operand" "0,m!*u,0")))]
   ""
   "#")
 
                                (const_int 16))
                   (match_operand:SI 2 "general_operand" "")))]
   "z_replacement_completed == 2 && X_REG_P (operands[1])"
-  [(set (reg:HI D_REGNUM) (reg:HI X_REGNUM))
+  [(set (reg:HI D_REGNUM) (match_dup 5))
    (set (reg:HI X_REGNUM) (match_dup 3))
    (set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 4)))
    (set (reg:HI X_REGNUM) (plus:HI (plus:HI (reg:HI X_REGNUM)
                                            (const_int 0))
                                   (reg:HI CC_REGNUM)))]
   "operands[3] = m68hc11_gen_highpart (HImode, operands[2]);
-   operands[4] = m68hc11_gen_lowpart (HImode, operands[2]);")
+   if (X_REG_P (operands[2]))
+     {
+       operands[4] = gen_rtx_REG (HImode, HARD_X_REGNUM);
+       operands[5] = gen_rtx_REG (HImode, HARD_D_REGNUM);
+     }
+   else
+     {
+       operands[4] = m68hc11_gen_lowpart (HImode, operands[2]);
+       operands[5] = gen_rtx_REG (HImode, HARD_X_REGNUM);
+     }
+")
 
 (define_insn "addsi_ashift16"
   [(set (match_operand:SI 0 "register_operand" "=D")
   operands[4] = m68hc11_gen_lowpart (HImode, operands[2]);
 }")
 
-(define_insn "addsi_andshr16"
+(define_insn_and_split "addsi_andshr16"
   [(set (match_operand:SI 0 "register_operand" "=D")
           (plus:SI (and:SI (match_operand:SI 1 "general_operand" "%uim")
                           (const_int 65535))
                   (match_operand:SI 2 "general_operand" "0")))]
   ""
-  "#")
-
-(define_split
-  [(set (match_operand:SI 0 "register_operand" "")
-          (plus:SI (and:SI (match_operand:SI 1 "general_operand" "")
-                          (const_int 65535))
-                  (match_operand:SI 2 "general_operand" "")))]
+  "#"
   "z_replacement_completed == 2"
   [(set (reg:HI D_REGNUM) (plus:HI (reg:HI D_REGNUM) (match_dup 3)))
    (set (reg:HI X_REGNUM) (plus:HI (plus:HI (reg:HI X_REGNUM) (const_int 0)) (reg:HI CC_REGNUM)))]
    ""
    "#")
 
-(define_insn "*ashlsi3_const16_zexthi"
+(define_insn_and_split "*ashlsi3_const16_zexthi"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=D")
        (ashift:SI (zero_extend:HI 
                        (match_operand:HI 1 "general_operand" "duim*A"))
                   (const_int 16)))
    (clobber (match_scratch:HI 2 "=X"))]
    ""
-   "#")
-
-(define_split /* "*ashlsi3_const16_zexthi"*/
-  [(set (match_operand:SI 0 "nonimmediate_operand" "")
-       (ashift:SI (zero_extend:HI 
-                       (match_operand:HI 1 "general_operand" ""))
-                  (const_int 16)))
-   (clobber (match_scratch:HI 2 "=X"))]
+   "#"
    "reload_completed"
    [(set (reg:HI X_REGNUM) (match_dup 1))
     (set (reg:HI D_REGNUM) (const_int 0))]
    "")
 
 (define_insn "*ashlsi3_const1"
-  [(set (match_operand:SI 0 "non_push_operand" "=D,D,m,!*u,?*um")
-       (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,*um,0,0,*um")
+  [(set (match_operand:SI 0 "non_push_operand" "=D,D,D,m,*u,*u")
+       (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,m,*u,m,*u,m")
                   (const_int 1)))
-   (clobber (match_scratch:HI 2 "=X,X,&d,&d,&d"))]
+   (clobber (match_scratch:HI 2 "=X,X,X,&d,&d,&d"))]
    ""
    "*
 {
        (ashift:SI (match_dup 0)
                   (match_operand:HI 1 "const_int_operand" "")))
    (clobber (match_scratch:HI 2 "=y"))]
-   ""
+   "TARGET_M6811 /* See *ashlsi3 note.  */"
    "*
 {
   CC_STATUS_INIT;
 (define_insn "*ashlsi3"
   [(set (match_operand:SI 0 "register_operand" "+D,D")
        (ashift:SI (match_dup 0)
-                  (match_operand:HI 1 "general_operand" "y,m")))
+                  (match_operand:HI 1 "general_operand" "y,mi")))
    (clobber (match_scratch:HI 2 "=1,X"))]
    ""
    "*
      is not enough register in class A_REGS.
 
      Assuming that 'operands[1]' does not refer to the stack (which 
-     is true for 68hc11 only, we save temporary the value of Y.  */
+     is true for 68hc11 only, we save temporary the value of Y.
+
+     For 68HC12 we must also accept a constant because Z register is
+     disabled when compiling with -fomit-frame-pointer.  We can come up
+     with a reload problem and the *lshrsi3_const pattern was disabled
+     for that reason.  */
   if (!Y_REG_P (operands[2]))
     {
       rtx ops[1];
        (ashiftrt:SI (match_dup 0)
                     (match_operand:HI 1 "const_int_operand" "")))
    (clobber (match_scratch:HI 2 "=y"))]
-   ""
+   "TARGET_M6811 /* See *ashrsi3 note.  */"
    "*
 {
   CC_STATUS_INIT;
 (define_insn "*ashrsi3"
   [(set (match_operand:SI 0 "register_operand" "+D,D")
        (ashiftrt:SI (match_dup 0)
-                    (match_operand:HI 1 "general_operand" "y,m")))
+                    (match_operand:HI 1 "general_operand" "y,mi")))
    (clobber (match_scratch:HI 2 "=1,X"))]
    ""
    "*
      is not enough register in class A_REGS.
 
      Assuming that 'operands[1]' does not refer to the stack (which 
-     is true for 68hc11 only, we save temporary the value of Y.  */
+     is true for 68hc11 only, we save temporary the value of Y.
+
+     For 68HC12 we must also accept a constant because Z register is
+     disabled when compiling with -fomit-frame-pointer.  We can come up
+     with a reload problem and the *lshrsi3_const pattern was disabled
+     for that reason.  */
   if (!Y_REG_P (operands[2]))
     {
       rtx ops[1];
     }
 }")
 
-(define_insn "*lshrdi3_const32"
+(define_insn_and_split "*lshrdi3_const32"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=<,m,u")
        (lshiftrt:DI (match_operand:DI 1 "general_operand" "umi,umi,umi")
                     (const_int 32)))
    (clobber (match_scratch:HI 2 "=&A,d,d"))]
    ""
-   "#")
-
-(define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (lshiftrt:DI (match_operand:DI 1 "general_operand" "")
-                    (const_int 32)))
-   (clobber (match_scratch:HI 2 "=&A,d"))]
+   "#"
    "reload_completed"
    [(const_int 0)]
    "m68hc11_split_move (m68hc11_gen_lowpart (SImode, operands[0]),
     operands[7] = m68hc11_gen_highpart (HImode, operands[6]);
     operands[6] = m68hc11_gen_lowpart (HImode, operands[6]);")
 
-(define_insn "*lshrdi_const1"
+(define_insn_and_split "*lshrdi_const1"
   [(set (match_operand:DI 0 "non_push_operand" "=m,u")
        (lshiftrt:DI (match_operand:DI 1 "general_operand" "umi,umi")
                     (const_int 1)))
    (clobber (match_scratch:HI 2 "=d,d"))]
    ""
-   "#")
-
-(define_split
-  [(set (match_operand:DI 0 "non_push_operand" "")
-       (lshiftrt:DI (match_operand:DI 1 "general_operand" "")
-                    (const_int 1)))
-   (clobber (match_scratch:HI 2 ""))]
+   "#"
    "z_replacement_completed == 2"
    [(set (match_dup 2) (match_dup 3))
     (set (match_dup 2) (lshiftrt:HI (match_dup 2) (const_int 1)))
     #")
 
 (define_insn "*lshrsi3_const1"
-  [(set (match_operand:SI 0 "non_push_operand" "=D,m,*u")
-       (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "D*um,*um,*um")
+  [(set (match_operand:SI 0 "non_push_operand" "=D,D,D,m,*u,*u")
+       (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,m,*u,m,*u,m")
                     (const_int 1)))
-   (clobber (match_scratch:HI 2 "=X,&d,&d"))]
+   (clobber (match_scratch:HI 2 "=X,X,X,&d,&d,&d"))]
    ""
    "*
 {
        (lshiftrt:SI (match_dup 0)
                     (match_operand:HI 1 "const_int_operand" "")))
    (clobber (match_scratch:HI 2 "=y"))]
-   ""
+   "TARGET_M6811 /* See *lshrsi3 note.  */"
    "*
 {
   CC_STATUS_INIT;
 (define_insn "*lshrsi3"
   [(set (match_operand:SI 0 "register_operand" "+D,D")
        (lshiftrt:SI (match_dup 0)
-                    (match_operand:HI 1 "general_operand" "y,m")))
+                    (match_operand:HI 1 "general_operand" "y,mi")))
    (clobber (match_scratch:HI 2 "=1,X"))]
    ""
    "*
      is not enough register in class A_REGS.
 
      Assuming that 'operands[1]' does not refer to the stack (which 
-     is true for 68hc11 only, we save temporary the value of Y.  */
+     is true for 68hc11 only, we save temporary the value of Y.
+
+     For 68HC12 we must also accept a constant because Z register is
+     disabled when compiling with -fomit-frame-pointer.  We can come up
+     with a reload problem and the *lshrsi3_const pattern was disabled
+     for that reason.  */
   if (!Y_REG_P (operands[2]))
     {
       rtx ops[1];
     {
       FAIL;
     }
+
+  /* Note that for xxx_dbcc_dec_yy the gen_rtx_NE is only used to pass
+     the operator and its operands are not relevant.  */
   if (GET_MODE (operands[0]) == HImode)
     {
       emit_jump_insn (gen_m68hc12_dbcc_dec_hi (operands[0],
-                                              gen_rtx_NE (HImode),
+                                              gen_rtx_NE (HImode,
+                                                          operands[0],
+                                                          const1_rtx),
                                               operands[4]));
       DONE;
     }
   if (GET_MODE (operands[0]) == QImode)
     {
       emit_jump_insn (gen_m68hc12_dbcc_dec_qi (operands[0],
-                                              gen_rtx_NE (QImode),
+                                              gen_rtx_NE (QImode,
+                                                          operands[0],
+                                                          const1_rtx),
                                               operands[4]));
       DONE;
     }
                          gen_rtx_POST_INC (HImode,
                                   gen_rtx_REG (HImode, HARD_SP_REGNUM)));")
 
+;; Replace: "pshx; tfr d,x; stx 0,sp" into "pshd; tfr d,x"
+;;
+;; PR 14542: emit a use to pretend we need the value of initial register.
+;; Otherwise verify_local_live_at_start will abort due to a live change
+;; of that register.
+;;
+(define_peephole2
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (match_operand:HI 0 "hard_reg_operand" ""))
+   (set (match_dup 0)
+        (match_operand:HI 1 "hard_reg_operand" ""))
+   (set (mem:HI (reg:HI SP_REGNUM))
+        (match_dup 0))]
+  "TARGET_M6812"
+  [(use (match_dup 0))
+   (set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (match_dup 1))
+   (set (match_dup 0) (match_dup 1))]
+  "")
+
+;;
+;; Change: "ldd 0,sp; pulx" into  "puld"
+;; This sequence usually appears at end a functions.
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+        (mem:HI (reg:HI SP_REGNUM)))
+   (use (match_dup 0))
+   (set (match_operand:HI 1 "hard_reg_operand" "")
+        (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))]
+  "peep2_reg_dead_p (2, operands[1])"
+  [(set (match_dup 0) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))
+   (use (match_dup 0))]
+  "")
+
+;; Replace: "pshx; clr 0,sp; clr 1,sp" by "clr 1,-sp; clr 1,-sp"
+;; Appears to allocate local variables.
+(define_peephole2
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (match_operand:HI 0 "hard_reg_operand" ""))
+   (set (mem:QI (plus:HI (reg:HI SP_REGNUM) (const_int 1)))
+        (const_int 0))
+   (set (mem:QI (reg:HI SP_REGNUM))
+        (const_int 0))]
+  "TARGET_M6812"
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (const_int 0))]
+  "")
+
+;; Likewise for HI mode
+(define_peephole2
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (match_operand:HI 0 "hard_reg_operand" ""))
+   (set (mem:HI (reg:HI SP_REGNUM))
+        (const_int 0))]
+  "TARGET_M6812"
+  [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM)))
+        (const_int 0))]
+  "")
+;;--------------------------------------------------------------------
+;;- 
+;;--------------------------------------------------------------------
 ;;
 ;; Optimize memory<->memory moves when the value is also loaded in
 ;; a register.
   "")
 
 ;;
+;; Replace: "ldx #N; xgdx; addd <var>; xgdx" by "ldab #N; ldx <var>; abx"
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "const_int_operand" ""))
+   (set (match_dup 0)
+       (plus:HI (match_dup 0)
+                (match_operand:HI 2 "general_operand" "")))
+   (match_scratch:QI 3 "d")]
+  "TARGET_M6811 && (INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0x0ff)"
+  [(set (match_dup 3) (match_dup 4))
+   (set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (plus:HI (zero_extend:HI (match_dup 3)) (match_dup 0)))]
+  "operands[4] = m68hc11_gen_lowpart (QImode, operands[1]);")
+
+;;
+;; Replace: "ldx #N; xgdx; addd <var>; xgdx" by "ldab #N; ldx <var>; abx"
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "const_int_operand" ""))
+   (set (match_dup 0)
+       (plus:HI (match_dup 0)
+                (match_operand:HI 2 "general_operand" "")))]
+  "TARGET_M6812"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))]
+  "")
+
+;;
 ;; Optimize an address register increment and a compare to use
 ;; a PRE_INC or PRE_DEC addressing mode (disabled on the tst insn
 ;; before reload, but can be enabled after).
   "")
 
 ;;
+;;
+;;
+(define_peephole2
+  [(parallel 
+     [(set (match_operand:SI 0 "hard_reg_operand" "")
+       (ashift:SI (match_operand:SI 1 "general_operand" "")
+                  (const_int 1)))
+      (clobber (match_scratch:HI 2 ""))])
+   (set (match_operand:HI 3 "nonimmediate_operand" "") (reg:HI D_REGNUM))
+   (set (match_operand:HI 4 "nonimmediate_operand" "") (reg:HI X_REGNUM))]
+  "!X_REG_P (operands[1])
+   && peep2_reg_dead_p (2, gen_rtx_REG (HImode, D_REGNUM))
+   && peep2_reg_dead_p (3, gen_rtx_REG (HImode, X_REGNUM))"
+  [(set (reg:HI D_REGNUM) (match_dup 5))
+   (set (reg:HI D_REGNUM) (ashift:HI (reg:HI D_REGNUM) (const_int 1)))
+   (set (match_dup 3) (reg:HI D_REGNUM))
+   (set (reg:HI D_REGNUM) (match_dup 6))
+   (parallel [(set (reg:HI D_REGNUM)
+                  (rotate:HI (reg:HI D_REGNUM) (const_int 1)))
+              (clobber (reg:HI CC_REGNUM))])
+   (set (match_dup 4) (reg:HI D_REGNUM))]
+  "operands[5] = m68hc11_gen_lowpart (HImode, operands[1]);
+   operands[6] = m68hc11_gen_highpart (HImode, operands[1]);")
+
+;;
 ;; Replace a "ldd <mem>; psha; pshb" with a "ldx <mem>; pshx".
 ;;
 (define_peephole2
   "")
 
 ;;
+;; Remove one load when copying a value to/from memory and also
+;; to a register.  Take care not clobbering a possible register used
+;; by operand 2.
+;; Replace: "ldd 0,y; std 2,y; ldx 0,y" into "ldx 0,y; stx 2,y"
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+        (match_operand:HI 1 "general_operand" ""))
+   (set (match_operand:HI 2 "nonimmediate_operand" "") (match_dup 0))
+   (set (match_operand:HI 3 "hard_reg_operand" "") (match_dup 1))]
+  "peep2_reg_dead_p (2, operands[0])
+   && !side_effects_p (operands[1])
+   && !side_effects_p (operands[2])
+   && !reg_mentioned_p (operands[3], operands[2])"
+  [(set (match_dup 3) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+  "")
+
+;;
 ;; Replace a "ldd <mem>; addd #N; std <mem>" into a
 ;; "ldx <mem>; leax; stx <mem>" if we have a free X/Y register
 ;; and the constant is small.
   "if (reg_mentioned_p (operands[4], operands[1])) FAIL;
    if (reg_mentioned_p (operands[4], operands[3])) FAIL;")
 
+;;--------------------------------------------------------------------
+;;- Bset peephole2
+;;--------------------------------------------------------------------
+;; These peepholes try to replace some logical sequences by 'bset' and 'bclr'.
+;;
+;; Replace 'ldab <mem>; orab #N; stab <mem>' by 'bset <mem> #N'.
+;; Register D must be dead and there must be no register side effects for mem.
+;; The <mem> *can* be volatile this is why we must not use 'side_effects_p'.
+;; The good side effect is that it makes the sequence atomic.
+;;
+(define_peephole2
+  [(set (match_operand:QI 0 "hard_reg_operand" "")
+       (match_operand:QI 1 "nonimmediate_operand" ""))
+   (set (match_dup 0) (ior:QI (match_dup 0)
+                             (match_operand:QI 2 "const_int_operand" "")))
+   (set (match_dup 1) (match_dup 0))]
+  "(TARGET_M6812 || m68hc11_indirect_p (operands[1], QImode))
+   && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0)))
+   && peep2_reg_dead_p (3, operands[0])"
+  [(set (match_dup 1) (ior:QI (match_dup 1) (match_dup 2)))]
+  "")
+
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "nonimmediate_operand" ""))
+   (set (match_dup 0) (ior:HI (match_dup 0)
+                             (match_operand:HI 2 "const_int_operand" "")))
+   (set (match_dup 1) (match_dup 0))]
+  "(TARGET_M6812 || m68hc11_indirect_p (operands[1], HImode))
+   && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0)))
+   && peep2_reg_dead_p (3, operands[0])"
+  [(set (match_dup 1) (ior:HI (match_dup 1) (match_dup 2)))]
+  "")
+
+;;--------------------------------------------------------------------
+;;- Bclr peephole2
+;;--------------------------------------------------------------------
+;; Replace 'ldab <mem>; andab #N; stab <mem>' by 'bclr <mem> #N'.
+;; See Bset peephole2.
+;;
+(define_peephole2
+  [(set (match_operand:QI 0 "hard_reg_operand" "")
+       (match_operand:QI 1 "nonimmediate_operand" ""))
+   (set (match_dup 0) (and:QI (match_dup 0)
+                             (match_operand:QI 2 "const_int_operand" "")))
+   (set (match_dup 1) (match_dup 0))]
+  "(TARGET_M6812 || m68hc11_indirect_p (operands[1], QImode))
+   && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0)))
+   && peep2_reg_dead_p (3, operands[0])"
+  [(set (match_dup 1) (and:QI (match_dup 1) (match_dup 2)))]
+  "")
+
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "nonimmediate_operand" ""))
+   (set (match_dup 0) (and:HI (match_dup 0)
+                             (match_operand:HI 2 "const_int_operand" "")))
+   (set (match_dup 1) (match_dup 0))]
+  "(TARGET_M6812 || m68hc11_indirect_p (operands[1], HImode))
+   && (GET_CODE (operands[1]) != MEM || !auto_inc_p (XEXP (operands[1], 0)))
+   && peep2_reg_dead_p (3, operands[0])"
+  [(set (match_dup 1) (and:HI (match_dup 1) (match_dup 2)))]
+  "")
+
+
+;;--------------------------------------------------------------------
+;;- Compare peephole2
+;;--------------------------------------------------------------------
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "hard_reg_operand" ""))
+   (set (match_dup 1) (plus:HI (match_dup 1) 
+                               (match_operand:HI 2 "const_int_operand" "")))
+   (set (cc0) (match_dup 0))]
+  "peep2_reg_dead_p (3, operands[0]) && !Z_REG_P (operands[1])"
+  [(set (match_dup 1) (plus:HI (match_dup 1) (match_dup 2)))
+   (set (cc0) (compare (match_dup 1) (match_dup 2)))]
+  "")
+
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "hard_reg_operand" ""))
+   (set (match_operand:HI 2 "hard_reg_operand" "")
+        (plus:HI (match_dup 2) 
+                 (match_operand:HI 3 "const_int_operand" "")))
+   (set (match_operand:HI 4 "memory_operand" "") (match_dup 2))
+   (set (cc0) (match_operand:HI 5 "hard_reg_operand" ""))]
+  "peep2_reg_dead_p (4, operands[5]) && !Z_REG_P (operands[2])
+   && !reg_mentioned_p (operands[2], operands[4])
+
+   && ((rtx_equal_p (operands[5], operands[0])
+        && rtx_equal_p (operands[2], operands[1]))
+
+       || (rtx_equal_p (operands[5], operands[1])
+           && rtx_equal_p (operands[2], operands[0])))"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 2) (plus:HI (match_dup 2) (match_dup 3)))
+   (set (match_dup 4) (match_dup 2))
+   (set (cc0) (compare (match_dup 2) (match_dup 3)))]
+  "")
+
+
+;;--------------------------------------------------------------------
+;;- Load peephole2
+;;--------------------------------------------------------------------
+;;
+;; Optimize initialization of 2 hard regs from the same memory location
+;; Since we can't copy easily X, Y and D to each other, load the 2 registers
+;; from the same memory location.
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "memory_operand" ""))
+   (set (match_operand:HI 2 "hard_reg_operand" "") (match_dup 0))]
+  "TARGET_M6811
+   && !side_effects_p (operands[1])
+   && !reg_mentioned_p (operands[0], operands[1])"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 1))]
+  "")
+
+;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N".
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "nonimmediate_operand" "") (const_int 0))
+   (set (match_operand:HI 1 "nonimmediate_operand" "") (const_int 0))
+   (set (match_operand:HI 2 "nonimmediate_operand" "") (const_int 0))
+   (set (match_operand:HI 3 "nonimmediate_operand" "") (const_int 0))
+   (match_scratch:HI 4 "d")]
+  ""
+  [(set (match_dup 4) (const_int 0))
+   (set (match_dup 0) (match_dup 4))
+   (set (match_dup 1) (match_dup 4))
+   (set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 4))]
+  "")
+
+;;
+;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N".
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "nonimmediate_operand" "") (const_int 0))
+   (set (match_operand:HI 1 "nonimmediate_operand" "") (const_int 0))
+   (set (match_operand:HI 2 "nonimmediate_operand" "") (const_int 0))
+   (match_scratch:HI 3 "d")]
+  ""
+  [(set (match_dup 3) (const_int 0))
+   (set (match_dup 0) (match_dup 3))
+   (set (match_dup 1) (match_dup 3))
+   (set (match_dup 2) (match_dup 3))]
+  "")
+
+;;
+;; Replace "ldd #N; addd <op>" with "ldd <op>; addd #N".
+;;
+(define_peephole2
+  [(set (match_operand:HI 0 "hard_reg_operand" "") (const_int 0))
+   (set (match_operand:HI 1 "push_operand" "") (match_dup 0))
+   (set (match_operand:HI 2 "push_operand" "") (match_dup 0))
+   (set (match_operand:HI 3 "push_operand" "") (match_dup 0))
+   (match_scratch:HI 4 "x")]
+  "TARGET_M6811 && D_REG_P (operands[0]) && peep2_reg_dead_p (4, operands[0])"
+  [(set (match_dup 4) (const_int 0))
+   (set (match_dup 1) (match_dup 4))
+   (set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 4))]
+  "")
+
 ;;
 ;; This peephole catches the address computations generated by the reload
 ;; pass. 
   return \"sts\\t%t0\\n\\tld%0\\t%t0\";
 }
 ")
+
+(define_peephole
+  [(set (match_operand:HI 0 "hard_reg_operand" "")
+       (match_operand:HI 1 "memory_operand" ""))
+   (set (match_operand:HI 2 "hard_reg_operand" "") (match_dup 0))]
+  "TARGET_M6811
+   && !side_effects_p (operands[1])
+   && !reg_mentioned_p (operands[0], operands[1])"
+  "*
+{
+  rtx ops[2];
+
+  ops[0] = operands[0];
+  ops[1] = operands[1];
+  m68hc11_gen_movhi (insn, ops);
+  ops[0] = operands[2];
+  m68hc11_gen_movhi (insn, ops);
+  return \"\";
+}")
+
+;; Peephole for Z register replacement.
+;; Avoid to use _.tmp register when comparing D and X if we can compare
+;; with soft register
+(define_peephole
+  [(set (match_operand:HI 0 "hard_reg_operand" "") (reg:HI SOFT_XY_REGNUM))
+   (set (reg:HI SOFT_TMP_REGNUM) (match_dup 0))
+   (set (cc0) (compare (match_operand:HI 2 "hard_reg_operand" "")
+                       (reg:HI SOFT_TMP_REGNUM)))]
+  "X_REG_P (operands[0]) || Y_REG_P (operands[0])"
+  "*
+{
+  rtx ops[2];
+
+  ops[0] = operands[0];
+  ops[1] = operands[1];
+  m68hc11_gen_movhi (insn, ops);
+  return \"cp%2\\t%1\";
+}")