ubuntu-buildroot/output/build/host-gcc-initial-11.4.0/gcc/config/h8300/jumpcall.md

285 lines
8.2 KiB
Markdown
Raw Permalink Normal View History

2024-04-01 15:19:46 +00:00
;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------
;; Conditional jump instructions
(define_expand "cbranch<mode>4"
[(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator"
[(match_operand:QHSI 1 "h8300_dst_operand")
(match_operand:QHSI 2 "h8300_src_operand")])
(label_ref (match_operand 3 ""))
(pc)))]
"")
(define_insn_and_split "*branch"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operand:QHSI 1 "h8300_dst_operand" "rQ")
(match_operand:QHSI 2 "h8300_src_operand" "rQi")])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
"#"
"reload_completed"
[(set (reg:H8cc CC_REG)
(compare:H8cc (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (match_op_dup 0
[(reg:H8cc CC_REG) (const_int 0)])
(label_ref (match_dup 3)) (pc)))]
"")
(define_insn "*branch_1"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
[(reg:H8cc CC_REG) (const_int 0)])
(label_ref (match_operand 0 "" ""))
(pc)))]
"reload_completed"
{
if (get_attr_length (insn) == 2)
return "b%j1 %l0";
else if (get_attr_length (insn) == 4)
return "b%j1 %l0:16";
else
return "b%k1 .Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:";
}
[(set_attr "type" "branch")])
(define_insn "*branch_1_false"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
[(reg:H8cc CC_REG) (const_int 0)])
(pc)
(label_ref (match_operand 0 "" ""))))]
"reload_completed"
{
if (get_attr_length (insn) == 2)
return "b%k1 %l0";
else if (get_attr_length (insn) == 4)
return "b%k1 %l0:16";
else
return "b%j1 .Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:";
}
[(set_attr "type" "branch")])
;; The brabc/brabs patterns have been disabled because their length computation
;; is horribly broken. When we call out to a function via a SYMBOL_REF we get
;; bogus default and minimum lengths. The trick used by the PA port seems to
;; fix the minimum, but not the default length. The broken lengths can lead
;; to bogusly using a short jump when a long jump was needed and thus
;; incorrect code.
;;
;; Given the restricted addressing modes for operand 1, we could probably just
;; open-code the necessary length computation in the two affected patterns
;; rather than using a function call. I think that would fix this problem.
(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)))]
"0 && 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")])
(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)))]
"0 && 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")])
;; 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")))])
;; 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 "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 "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)))])