8.2 KiB
;; ---------------------------------------------------------------------- ;; JUMP INSTRUCTIONS ;; ----------------------------------------------------------------------
;; Conditional jump instructions
(define_expand "cbranch4" [(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" [(set (pc) (match_operand:P 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "" { if (mode == E_HImode) return "jmp @%0"; if (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_" [(set (pc) (match_operand:P 0 "jump_address_operand" "Vr"))] "" { if (mode == E_HImode) return "jmp @%0"; if (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_" [(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_" [(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)))])