view gcc/config/h8300/jumpcall.md @ 19:2b5abeee2509 default tip

update gcc11
author anatofuz
date Mon, 25 May 2020 07:50:57 +0900
parents
children
line wrap: on
line source

;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------

;; Conditional jump instructions

(define_expand "cbranchqi4"
  [(use (match_operator 0 "ordered_comparison_operator"
         [(match_operand:QI 1 "h8300_dst_operand" "")
          (match_operand:QI 2 "h8300_src_operand" "")]))
   (use (match_operand 3 ""))]
  ""
  {
    h8300_expand_branch (operands);
    DONE;
  })

(define_expand "cbranchhi4"
  [(use (match_operator 0 "ordered_comparison_operator"
         [(match_operand:HI 1 "h8300_dst_operand" "")
          (match_operand:HI 2 "h8300_src_operand" "")]))
   (use (match_operand 3 ""))]
  ""
  {
    h8300_expand_branch (operands);
    DONE;
  })

(define_expand "cbranchsi4"
  [(use (match_operator 0 "ordered_comparison_operator"
         [(match_operand:SI 1 "h8300_dst_operand" "")
          (match_operand:SI 2 "h8300_src_operand" "")]))
   (use (match_operand 3 ""))]
  ""
  {
    h8300_expand_branch (operands);
    DONE;
  })

(define_insn "branch"
  [(set (pc)
	(if_then_else (match_operator 2 "comparison_operator"
		       [(cc0) (const_int 0)])
		      (match_operand 0 "pc_or_label_operand" "")
		      (match_operand 1 "pc_or_label_operand" "")))]
  "operands[0] == pc_rtx || operands[1] == pc_rtx"
{
  if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
      && (GET_CODE (operands[2]) == GT
	  || GET_CODE (operands[2]) == GE
	  || GET_CODE (operands[2]) == LE
	  || GET_CODE (operands[2]) == LT))
    {
      cc_status.flags &= ~CC_OVERFLOW_UNUSABLE;
      return 0;
    }

  if (operands[0] != pc_rtx)
    {
      if (get_attr_length (insn) == 2)
	return "b%j2	%l0";
      else if (get_attr_length (insn) == 4)
	return "b%j2	%l0:16";
      else
	return "b%k2	.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
    }
  else
    {
      if (get_attr_length (insn) == 2)
	return "b%k2	%l1";
      else if (get_attr_length (insn) == 4)
	return "b%k2	%l1:16";
      else
	return "b%j2	.Lh8BR%=\;jmp	@%l1\\n.Lh8BR%=:";
    }
}
 [(set_attr "type" "branch")
   (set_attr "cc" "none")])

(define_insn "*brabc"
  [(set (pc)
	(if_then_else (eq (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
					(const_int 1)
					(match_operand:QI 2 "immediate_operand" "n"))
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_H8300SX"
{
  switch (get_attr_length (insn)
	  - h8300_insn_length_from_table (insn, operands))
    {
    case 2:
      return "bra/bc	%2,%R1,%l0";
    case 4:
      return "bra/bc	%2,%R1,%l0:16";
    default:
      return "bra/bs	%2,%R1,.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
    }
}
  [(set_attr "type" "bitbranch")
   (set_attr "length_table" "bitbranch")
   (set_attr "cc" "none")])

(define_insn "*brabs"
  [(set (pc)
	(if_then_else (ne (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
					(const_int 1)
					(match_operand:QI 2 "immediate_operand" "n"))
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_H8300SX"
{
  switch (get_attr_length (insn)
	  - h8300_insn_length_from_table (insn, operands))
    {
    case 2:
      return "bra/bs	%2,%R1,%l0";
    case 4:
      return "bra/bs	%2,%R1,%l0:16";
    default:
      return "bra/bc	%2,%R1,.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
    }
}
  [(set_attr "type" "bitbranch")
   (set_attr "length_table" "bitbranch")
   (set_attr "cc" "none")])

;; Unconditional and other jump instructions.

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
{
  if (final_sequence != 0)
    {
      if (get_attr_length (insn) == 2)
	return "bra/s	%l0";
      else
	{
	  /* The branch isn't short enough to use bra/s.  Output the
	     branch and delay slot in their normal order.

	     If this is a backward branch, it will now be branching two
	     bytes further than previously thought.  The length-based
	     test for bra vs. jump is very conservative though, so the
	     branch will still be within range.  */
	  rtx_sequence *seq;
	  int seen;

	  seq = final_sequence;
	  final_sequence = 0;
	  final_scan_insn (seq->insn (1), asm_out_file, optimize, 1, & seen);
	  final_scan_insn (seq->insn (0), asm_out_file, optimize, 1, & seen);
	  seq->insn (1)->set_deleted ();
	  return "";
	}
    }
  else if (get_attr_length (insn) == 2)
    return "bra	%l0";
  else if (get_attr_length (insn) == 4)
    return "bra	%l0:16";
  else
    return "jmp	@%l0";
}
  [(set_attr "type" "branch")
   (set (attr "delay_slot")
	(if_then_else (match_test "TARGET_H8300SX")
		      (const_string "jump")
		      (const_string "none")))
   (set_attr "cc" "none")])

;; This is a define expand, because pointers may be either 16 or 32 bits.

(define_expand "tablejump"
  [(parallel [(set (pc) (match_operand 0 "register_operand" ""))
	      (use (label_ref (match_operand 1 "" "")))])]
  ""
  "")

(define_insn "tablejump<mode>"
  [(set (pc) (match_operand:P 0 "register_operand" "r"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  {
    if (<MODE>mode == E_HImode)
      return "jmp	@%0";
    if (<MODE>mode == E_SImode)
      return "jmp	@%S0";
    abort ();
  }
  [(set_attr "cc" "none")
   (set_attr "length" "2")])

;; This is a define expand, because pointers may be either 16 or 32 bits.

(define_expand "indirect_jump"
  [(set (pc) (match_operand 0 "jump_address_operand" ""))]
  ""
  "")

(define_insn "*indirect_jump_<mode>"
  [(set (pc) (match_operand:P 0 "jump_address_operand" "Vr"))]
  ""
  {
    if (<MODE>mode == E_HImode)
      return "jmp	@%0";
    if (<MODE>mode == E_SImode)
      return "jmp	@%S0";
    abort ();
  }
  [(set_attr "cc" "none")
   (set_attr "length" "2")])

;; Call subroutine with no return value.

;; ??? Even though we use HImode here, this works on the H8/300H and H8S.

(define_expand "call"
  [(call (match_operand:QI 0 "call_expander_operand" "")
	 (match_operand 1 "general_operand" ""))]
  ""
  {
    if (!register_operand (XEXP (operands[0], 0), Pmode)
	&& GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
      XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
  })

(define_insn "call_insn_<mode>"
  [(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
	         (match_operand:P 1 "general_operand" "g"))]
  ""
{
  rtx xoperands[1];
  xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
  gcc_assert (GET_MODE (operands[0]) == Pmode);
  if (GET_CODE (XEXP (xoperands[0], 0)) == SYMBOL_REF
      && (SYMBOL_REF_FLAGS (XEXP (xoperands[0], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
    output_asm_insn ("jsr\\t@%0:8", xoperands);
  else
    output_asm_insn ("jsr\\t%0", xoperands);
  return "";
}
  [(set_attr "type" "call")
   (set (attr "length")
	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
		      (const_int 2)
		      (const_int 4)))])

;; Call subroutine, returning value in operand 0
;; (which must be a hard register).

;; ??? Even though we use HImode here, this works on the H8/300H and H8S.

(define_expand "call_value"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "call_expander_operand" "")
	      (match_operand 2 "general_operand" "")))]
  ""
  {
    if (!register_operand (XEXP (operands[1], 0), Pmode)
	&& GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
      XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
  })

(define_insn "call_value_insn_<mode>"
  [(set (match_operand 0 "" "=r")
	(call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
		      (match_operand:P 2 "general_operand" "g")))]
  ""
{
  rtx xoperands[2];
  gcc_assert (GET_MODE (operands[1]) == Pmode);
  xoperands[0] = operands[0];
  xoperands[1] = gen_rtx_MEM (QImode, operands[1]);
  if (GET_CODE (XEXP (xoperands[1], 0)) == SYMBOL_REF
      && (SYMBOL_REF_FLAGS (XEXP (xoperands[1], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
    output_asm_insn ("jsr\\t@%1:8", xoperands);
  else
    output_asm_insn ("jsr\\t%1", xoperands);
  return "";
}
  [(set_attr "type" "call")
   (set (attr "length")
	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
		      (const_int 2)
		      (const_int 4)))])