;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
;; The H8/300 has given 1/8th of its opcode space to bitfield
;; instructions so let's use them as well as we can.

;; You'll never believe all these patterns perform one basic action --
;; load a bit from the source, optionally invert the bit, then store it
;; in the destination (which is known to be zero).
;;
;; Combine obviously need some work to better identify this situation and
;; canonicalize the form better.

;;
;; Inverted loads with a 16bit destination.
;;

(define_insn_and_split ""
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(zero_extract:HI (xor:HI (match_operand:HI 1 "register_operand" "r")
				 (match_operand:HI 3 "const_int_operand" "n"))
			 (const_int 1)
			 (match_operand:HI 2 "const_int_operand" "n")))]
  "(TARGET_H8300SX)
    && (1 << INTVAL (operands[2])) == INTVAL (operands[3])"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (zero_extract:HI (xor:HI (match_dup 1) (match_dup 3))
				    (const_int 1)
				    (match_dup 2)))
	      (clobber (reg:CC CC_REG))])])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(zero_extract:HI (xor:HI (match_operand:HI 1 "register_operand" "r")
				 (match_operand:HI 3 "const_int_operand" "n"))
			 (const_int 1)
			 (match_operand:HI 2 "const_int_operand" "n")))
   (clobber (reg:CC CC_REG))]
  "(TARGET_H8300SX)
    && (1 << INTVAL (operands[2])) == INTVAL (operands[3])"
  "sub.w	%0,%0\;bild	%Z2,%Y1\;bst	#0,%X0"
  [(set_attr "length" "8")])

;;
;; Normal loads with a 32bit destination.
;;

(define_insn_and_split "*extzv_1_r"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(zero_extract:SI (match_operand:SI 1 "register_operand" "?0,r")
			 (const_int 1)
			 (match_operand 2 "const_int_operand" "n,n")))]
  "INTVAL (operands[2]) < 16"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (zero_extract:SI (match_dup 1) (const_int 1) (match_dup 2)))
	      (clobber (reg:CC CC_REG))])])

(define_insn "*extzv_1_r_clobber_flags"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(zero_extract:SI (match_operand:SI 1 "register_operand" "?0,r")
			 (const_int 1)
			 (match_operand 2 "const_int_operand" "n,n")))
   (clobber (reg:CC CC_REG))]
  "INTVAL (operands[2]) < 16"
{
  return output_simode_bld (0, operands);
}
  [(set_attr "length" "8,6")])

;;
;; Inverted loads with a 32bit destination.
;;

(define_insn_and_split "*extzv_1_r_inv"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(zero_extract:SI (xor:SI (match_operand:SI 1 "register_operand" "?0,r")
				 (match_operand 3 "const_int_operand" "n,n"))
			 (const_int 1)
			 (match_operand 2 "const_int_operand" "n,n")))]
  "INTVAL (operands[2]) < 16
    && (1 << INTVAL (operands[2])) == INTVAL (operands[3])"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (zero_extract:SI (xor:SI (match_dup 1) (match_dup 3))
				    (const_int 1)
				    (match_dup 2)))
	      (clobber (reg:CC CC_REG))])])

(define_insn "*extzv_1_r_inv_clobber_flags"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(zero_extract:SI (xor:SI (match_operand:SI 1 "register_operand" "?0,r")
				 (match_operand 3 "const_int_operand" "n,n"))
			 (const_int 1)
			 (match_operand 2 "const_int_operand" "n,n")))
   (clobber (reg:CC CC_REG))]
  "INTVAL (operands[2]) < 16
    && (1 << INTVAL (operands[2])) == INTVAL (operands[3])"
{
  return output_simode_bld (1, operands);
}
  [(set_attr "length" "8,6")])

(define_expand "insv"
  [(set (zero_extract:HI (match_operand:HI 0 "general_operand" "")
			 (match_operand:HI 1 "general_operand" "")
			 (match_operand:HI 2 "general_operand" ""))
	(match_operand:HI 3 "general_operand" ""))]
  "TARGET_H8300SX"
  {
    if (GET_CODE (operands[1]) == CONST_INT
	&& GET_CODE (operands[2]) == CONST_INT
	&& INTVAL (operands[1]) <= 8
	&& INTVAL (operands[2]) >= 0
	&& INTVAL (operands[1]) + INTVAL (operands[2]) <= 8
	&& memory_operand (operands[0], GET_MODE (operands[0])))
      {
	/* If the source operand is zero, it's better to use AND rather
	   than BFST.  Likewise OR if the operand is all ones.  */
	if (GET_CODE (operands[3]) == CONST_INT)
	  {
	    HOST_WIDE_INT mask = (1 << INTVAL (operands[1])) - 1;
	    if ((INTVAL (operands[3]) & mask) == 0)
	      FAIL;
	    if ((INTVAL (operands[3]) & mask) == mask)
	      FAIL;
	  }
	if (! bit_memory_operand (operands[0], GET_MODE (operands[0])))
	  {
	    if (!can_create_pseudo_p ())
	      FAIL;
	    operands[0] =  replace_equiv_address (operands[0], force_reg (Pmode,
						  XEXP (operands[0], 0)));
	  }
	operands[3] = gen_lowpart (QImode, operands[3]);
	if (! operands[3])
	  FAIL;
	if (! register_operand (operands[3], QImode))
	  {
	    if (!can_create_pseudo_p ())
	      FAIL;
	    operands[3] = force_reg (QImode, operands[3]);
	  }
	emit_insn (gen_bfst (adjust_address (operands[0], QImode, 0),
					     operands[3], operands[1], operands[2]));
	DONE;
      }
    FAIL;
  })

(define_insn_and_split ""
  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "n"))
	(match_operand:HI 2 "register_operand" "r"))]
  ""
  "#"
  "&& reload_completed"
  [(parallel [(set (zero_extract:HI (match_dup 0) (const_int 1) (match_dup 1))
		   (match_dup 2))
	      (clobber (reg:CC CC_REG))])])

(define_insn ""
  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "n"))
	(match_operand:HI 2 "register_operand" "r"))
   (clobber (reg:CC CC_REG))]
  ""
  "bld	#0,%R2\;bst	%Z1,%Y0 ; i1"
  [(set_attr "length" "4")])

(define_expand "extzv"
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extract:HI (match_operand:HI 1 "bit_operand" "")
			 (match_operand:HI 2 "general_operand" "")
			 (match_operand:HI 3 "general_operand" "")))]
  "TARGET_H8300SX"
  {
    if (GET_CODE (operands[2]) == CONST_INT
	&& GET_CODE (operands[3]) == CONST_INT
	&& INTVAL (operands[2]) <= 8
	&& INTVAL (operands[3]) >= 0
	&& INTVAL (operands[2]) + INTVAL (operands[3]) <= 8
	&& memory_operand (operands[1], QImode))
      {
	rtx temp;

	/* Optimize the case where we're extracting into a paradoxical
	   subreg.  It's only necessary to extend to the inner reg.  */
	if (GET_CODE (operands[0]) == SUBREG
	    && subreg_lowpart_p (operands[0])
	    && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0])))
		< GET_MODE_SIZE (GET_MODE (operands[0])))
	    && (GET_MODE_CLASS (GET_MODE (SUBREG_REG (operands[0])))
		== MODE_INT))
	   operands[0] = SUBREG_REG (operands[0]);

	if (!can_create_pseudo_p ())
	  temp = gen_lowpart (QImode, operands[0]);
	else
	  temp = gen_reg_rtx (QImode);
	if (! temp)
	  FAIL;
        if (! bit_memory_operand (operands[1], QImode))
	  {
	    if (!can_create_pseudo_p ())
	      FAIL;
	    operands[1] = replace_equiv_address (operands[1],
						 force_reg (Pmode, XEXP (operands[1], 0)));
	  }
	emit_insn (gen_bfld (temp, operands[1], operands[2], operands[3]));
	convert_move (operands[0], temp, 1);
	DONE;
      }
    FAIL;
  })

;; BAND, BOR, and BXOR patterns

(define_insn_and_split ""
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 4 "bit_operator"
	 [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 2 "immediate_operand" "n"))
	  (match_operand:HI 3 "bit_operand" "0")]))]
  ""
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (match_op_dup 4 [(zero_extract:HI (match_dup 1)
						     (const_int 1)
						     (match_dup 2))
				    (match_dup 3)]))
	      (clobber (reg:CC CC_REG))])])

(define_insn ""
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 4 "bit_operator"
	 [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 2 "immediate_operand" "n"))
	  (match_operand:HI 3 "bit_operand" "0")]))
   (clobber (reg:CC CC_REG))]
  ""
  "bld	%Z2,%Y1\;b%c4	#0,%R0\;bst	#0,%R0; bl1"
  [(set_attr "length" "6")])

(define_insn_and_split ""
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 5 "bit_operator"
	 [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 2 "immediate_operand" "n"))
	  (zero_extract:HI (match_operand:HI 3 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 4 "immediate_operand" "n"))]))]
  ""
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (match_op_dup 5 [(zero_extract:HI (match_dup 1)
						     (const_int 1)
						     (match_dup 2))
				    (zero_extract:HI (match_dup 3)
						     (const_int 1)
						     (match_dup 4))]))
	      (clobber (reg:CC CC_REG))])])

(define_insn ""
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 5 "bit_operator"
	 [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 2 "immediate_operand" "n"))
	  (zero_extract:HI (match_operand:HI 3 "register_operand" "r")
			   (const_int 1)
			   (match_operand:HI 4 "immediate_operand" "n"))]))
   (clobber (reg:CC CC_REG))]
  ""
  "bld	%Z2,%Y1\;b%c5	%Z4,%Y3\;bst	#0,%R0; bl3"
  [(set_attr "length" "6")])

(define_insn_and_split "bfld"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(zero_extract:QI (match_operand:QI 1 "bit_memory_operand" "WU")
			 (match_operand:QI 2 "immediate_operand" "n")
			 (match_operand:QI 3 "immediate_operand" "n")))]
  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0)
		   (zero_extract:QI (match_dup 1) (match_dup 2) (match_dup 3)))
	      (clobber (reg:CC CC_REG))])])

(define_insn "bfld_clobber_flags"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(zero_extract:QI (match_operand:QI 1 "bit_memory_operand" "WU")
			 (match_operand:QI 2 "immediate_operand" "n")
			 (match_operand:QI 3 "immediate_operand" "n")))
   (clobber (reg:CC CC_REG))]
  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
{
  operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3])))
			 - (1 << INTVAL (operands[3])));
  return "bfld	%2,%1,%R0";
}
  [(set_attr "length_table" "bitfield")])

(define_insn_and_split "bfst"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
			 (match_operand:QI 2 "immediate_operand" "n")
			 (match_operand:QI 3 "immediate_operand" "n"))
	(match_operand:QI 1 "register_operand" "r"))]
  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
  "#"
  "&& reload_completed"
  [(parallel [(set (zero_extract:QI (match_dup 0) (match_dup 2) (match_dup 3))
		   (match_dup 1))
	      (clobber (reg:CC CC_REG))])])

(define_insn "bfst_clobber_flags"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
			 (match_operand:QI 2 "immediate_operand" "n")
			 (match_operand:QI 3 "immediate_operand" "n"))
	(match_operand:QI 1 "register_operand" "r"))
   (clobber (reg:CC CC_REG))]
  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
{
  operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3])))
			 - (1 << INTVAL (operands[3])));
  return "bfst	%R1,%2,%0";
}
  [(set_attr "length_table" "bitfield")])

;;(define_insn "*bstzhireg"
;;  [(set (match_operand:HI 0 "register_operand" "=r")
;;	(match_operator:HI 1 "eqne_operator" [(cc0) (const_int 0)]))]
;;  "TARGET_H8300SX"
;;  "mulu.w	#0,%T0\;b%k1	.Lh8BR%=\;inc.w	#1,%T0\\n.Lh8BR%=:")

;;(define_insn_and_split "*cmpstz"
;;  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU,WU")
;;			 (const_int 1)
;;			 (match_operand:QI 1 "immediate_operand" "n,n"))
;;	(match_operator:QI 2 "eqne_operator"
;;	 [(match_operand 3 "h8300_dst_operand" "r,rQ")
;;	  (match_operand 4 "h8300_src_operand" "I,rQi")]))]
;;  "TARGET_H8300SX
;;   && (GET_MODE (operands[3]) == GET_MODE (operands[4])
;;       || GET_CODE (operands[4]) == CONST_INT)
;;   && GET_MODE_CLASS (GET_MODE (operands[3])) == MODE_INT
;;   && GET_MODE_SIZE (GET_MODE (operands[3])) <= 4"
;;  "#"
;;  "reload_completed"
;;  [(set (cc0) (match_dup 5))
;;   (set (zero_extract:QI (match_dup 0) (const_int 1) (match_dup 1))
;;	(match_op_dup:QI 2 [(cc0) (const_int 0)]))]
;;  {
;;    operands[5] = gen_rtx_COMPARE (VOIDmode, operands[3], operands[4]);
;;  })

;;(define_insn "*bstz"
;;  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
;;			 (const_int 1)
;;			 (match_operand:QI 1 "immediate_operand" "n"))
;;	(eq:QI (cc0) (const_int 0)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bstz	%1,%0"
;;  [(set_attr "length_table" "unary")])

;;(define_insn "*bistz"
;;  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
;;			 (const_int 1)
;;			 (match_operand:QI 1 "immediate_operand" "n"))
;;	(ne:QI (cc0) (const_int 0)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bistz	%1,%0"
;;  [(set_attr "length_table" "unary")])

;;(define_insn_and_split "*cmpcondbset"
;;  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
;;	(if_then_else:QI (match_operator 1 "eqne_operator"
;;			  [(match_operand 2 "h8300_dst_operand" "r,rQ")
;;			   (match_operand 3 "h8300_src_operand" "I,rQi")])
;;			 (ior:QI (match_operand:QI 4 "bit_memory_operand" "0,0")
;;				 (match_operand:QI 5 "single_one_operand" "n,n"))
;;			 (match_dup 4)))]
;;  "TARGET_H8300SX"
;;  "#"
;;  "reload_completed"
;;  [(set (cc0) (match_dup 6))
;;   (set (match_dup 0)
;;	(if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)])
;;			 (ior:QI (match_dup 4) (match_dup 5))
;;			 (match_dup 4)))]
;;  {
;;    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
;;  })

;;(define_insn "*condbset"
;;  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
;;	(if_then_else:QI (match_operator:QI 2 "eqne_operator"
;;			  [(cc0) (const_int 0)])
;;			 (ior:QI (match_operand:QI 3 "bit_memory_operand" "0")
;;				 (match_operand:QI 1 "single_one_operand" "n"))
;;			 (match_dup 3)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bset/%j2\t%V1,%0"
;;  [(set_attr "length_table" "logicb")])

;;(define_insn_and_split "*cmpcondbclr"
;;  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
;;	(if_then_else:QI (match_operator 1 "eqne_operator"
;;			  [(match_operand 2 "h8300_dst_operand" "r,rQ")
;;			   (match_operand 3 "h8300_src_operand" "I,rQi")])
;;			 (and:QI (match_operand:QI 4 "bit_memory_operand" "0,0")
;;				 (match_operand:QI 5 "single_zero_operand" "n,n"))
;;			 (match_dup 4)))]
;;  "TARGET_H8300SX"
;;  "#"
;;  "reload_completed"
;;  [(set (cc0) (match_dup 6))
;;   (set (match_dup 0)
;;	(if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)])
;;			 (and:QI (match_dup 4) (match_dup 5))
;;			 (match_dup 4)))]
;;  {
;;    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
;;  })

;;(define_insn "*condbclr"
;;  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
;;	(if_then_else:QI (match_operator:QI 2 "eqne_operator"
;;			  [(cc0) (const_int 0)])
;;			 (and:QI (match_operand:QI 3 "bit_memory_operand" "0")
;;				 (match_operand:QI 1 "single_zero_operand" "n"))
;;			 (match_dup 3)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bclr/%j2\t%W1,%0"
;;  [(set_attr "length_table" "logicb")])

;;(define_insn_and_split "*cmpcondbsetreg"
;;  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
;;	(if_then_else:QI (match_operator 1 "eqne_operator"
;;			  [(match_operand 2 "h8300_dst_operand" "r,rQ")
;;			   (match_operand 3 "h8300_src_operand" "I,rQi")])
;;			 (ior:QI (match_operand:QI 4 "bit_memory_operand" "0,0")
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 5 "register_operand" "r,r")))
;;			 (match_dup 4)))]
;;  "TARGET_H8300SX"
;;  "#"
;;  "reload_completed"
;;  [(set (cc0) (match_dup 6))
;;   (set (match_dup 0)
;;	(if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)])
;;			 (ior:QI (match_dup 4)
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 5 "register_operand" "r,r")))
;;			 (match_dup 4)))]
;;  {
;;    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
;;  })

;;(define_insn "*condbsetreg"
;;  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
;;	(if_then_else:QI (match_operator:QI 2 "eqne_operator"
;;			  [(cc0) (const_int 0)])
;;			 (ior:QI (match_operand:QI 3 "bit_memory_operand" "0")
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 1 "register_operand" "r")))
;;			 (match_dup 3)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bset/%j2\t%R1,%0"
;;  [(set_attr "length_table" "logicb")])

;;(define_insn_and_split "*cmpcondbclrreg"
;;  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
;;	(if_then_else:QI (match_operator 1 "eqne_operator"
;;			  [(match_operand 2 "h8300_dst_operand" "r,rQ")
;;			   (match_operand 3 "h8300_src_operand" "I,rQi")])
;;			 (and:QI (match_operand:QI 4 "bit_memory_operand" "0,0")
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 5 "register_operand" "r,r")))
;;			 (match_dup 4)))]
;;  "TARGET_H8300SX"
;;  "#"
;;  "reload_completed"
;;  [(set (cc0) (match_dup 6))
;;   (set (match_dup 0)
;;	(if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)])
;;			 (and:QI (match_dup 4)
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 5 "register_operand" "r,r")))
;;			 (match_dup 4)))]
;;  {
;;    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
;;  })

;;(define_insn "*condbclrreg"
;;  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
;;	(if_then_else:QI (match_operator:QI 2 "eqne_operator"
;;			  [(cc0) (const_int 0)])
;;			 (and:QI (match_operand:QI 3 "bit_memory_operand" "0")
;;				 (ashift:QI (const_int 1)
;;					    (match_operand:QI 1 "register_operand" "r")))
;;			 (match_dup 3)))]
;;  "TARGET_H8300SX && reload_completed"
;;  "bclr/%j2\t%R1,%0"
;;  [(set_attr "length_table" "logicb")])