xref: /netbsd-src/external/gpl3/gcc/dist/gcc/config/h8300/jumpcall.md (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1;; ----------------------------------------------------------------------
2;; JUMP INSTRUCTIONS
3;; ----------------------------------------------------------------------
4
5;; Conditional jump instructions
6
7(define_expand "cbranch<mode>4"
8  [(set (pc)
9	(if_then_else (match_operator 0 "ordered_comparison_operator"
10		        [(match_operand:QHSI 1 "h8300_dst_operand")
11			 (match_operand:QHSI 2 "h8300_src_operand")])
12		      (label_ref (match_operand 3 ""))
13		      (pc)))]
14  "")
15
16(define_insn_and_split "*branch"
17  [(set (pc)
18	(if_then_else (match_operator 0 "comparison_operator"
19		       [(match_operand:QHSI 1 "h8300_dst_operand" "rQ")
20			(match_operand:QHSI 2 "h8300_src_operand" "rQi")])
21		      (label_ref (match_operand 3 "" ""))
22		      (pc)))]
23  ""
24  "#"
25  "&& reload_completed"
26  [(set (match_dup 4)
27	(match_dup 5))
28   (set (pc)
29	(if_then_else (match_op_dup 0
30		       [(match_dup 4) (const_int 0)])
31		      (label_ref (match_dup 3)) (pc)))]
32  "
33{
34  machine_mode mode;
35
36  if (REG_P (operands[1])
37      && operands[2] == const0_rtx
38      && (GET_CODE (operands[0]) == EQ
39	  || GET_CODE (operands[0]) == NE
40	  || GET_CODE (operands[0]) == LT
41	  || GET_CODE (operands[0]) == GE
42	  /* Our tstxx insns will set ZN and clear V, so we can handle
43	     a couple additional cases.  */
44	  || GET_CODE (operands[0]) == LE
45	  || GET_CODE (operands[0]) == GT))
46    mode = E_CCZNmode;
47  else
48    mode = E_CCmode;
49  operands[4] = gen_rtx_REG (mode, CC_REG);
50  operands[5] = gen_rtx_COMPARE (mode, operands[1], operands[2]);
51}")
52
53(define_insn "*branch_1"
54  [(set (pc)
55	(if_then_else (match_operator 1 "comparison_operator"
56		       [(reg:H8cc CC_REG) (const_int 0)])
57		      (label_ref (match_operand 0 "" ""))
58		      (pc)))]
59  "reload_completed"
60{
61  if (get_attr_length (insn) == 2)
62    return "b%j1	%l0";
63  else if (get_attr_length (insn) == 4)
64    return "b%j1	%l0:16";
65  else
66    return "b%k1	.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
67}
68 [(set_attr "type" "branch")])
69
70
71(define_insn "*branch_1_false"
72  [(set (pc)
73	(if_then_else (match_operator 1 "comparison_operator"
74		       [(reg:H8cc CC_REG) (const_int 0)])
75		      (pc)
76		      (label_ref (match_operand 0 "" ""))))]
77  "reload_completed"
78{
79  if (get_attr_length (insn) == 2)
80    return "b%k1	%l0";
81  else if (get_attr_length (insn) == 4)
82    return "b%k1	%l0:16";
83  else
84    return "b%j1	.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
85}
86 [(set_attr "type" "branch")])
87
88;; The brabc/brabs patterns have been disabled because their length computation
89;; is horribly broken.  When we call out to a function via a SYMBOL_REF we get
90;; bogus default and minimum lengths.  The trick used by the PA port seems to
91;; fix the minimum, but not the default length.  The broken lengths can lead
92;; to bogusly using a short jump when a long jump was needed and thus
93;; incorrect code.
94;;
95;; Given the restricted addressing modes for operand 1, we could probably just
96;; open-code the necessary length computation in the two affected patterns
97;; rather than using a function call.  I think that would fix this problem.
98(define_insn "*brabc"
99  [(set (pc)
100	(if_then_else (eq (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
101					(const_int 1)
102					(match_operand:QI 2 "immediate_operand" "n"))
103			  (const_int 0))
104		      (label_ref (match_operand 0 "" ""))
105		      (pc)))]
106  "0 && TARGET_H8300SX"
107{
108  switch (get_attr_length (insn)
109	  - h8300_insn_length_from_table (insn, operands))
110    {
111    case 2:
112      return "bra/bc	%2,%R1,%l0";
113    case 4:
114      return "bra/bc	%2,%R1,%l0:16";
115    default:
116      return "bra/bs	%2,%R1,.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
117    }
118}
119  [(set_attr "type" "bitbranch")
120   (set_attr "length_table" "bitbranch")])
121
122(define_insn "*brabs"
123  [(set (pc)
124	(if_then_else (ne (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
125					(const_int 1)
126					(match_operand:QI 2 "immediate_operand" "n"))
127			  (const_int 0))
128		      (label_ref (match_operand 0 "" ""))
129		      (pc)))]
130  "0 && TARGET_H8300SX"
131{
132  switch (get_attr_length (insn)
133	  - h8300_insn_length_from_table (insn, operands))
134    {
135    case 2:
136      return "bra/bs	%2,%R1,%l0";
137    case 4:
138      return "bra/bs	%2,%R1,%l0:16";
139    default:
140      return "bra/bc	%2,%R1,.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:";
141    }
142}
143  [(set_attr "type" "bitbranch")
144   (set_attr "length_table" "bitbranch")])
145
146(define_insn_and_split ""
147  [(set (pc)
148	(if_then_else (match_operator 3 "eqne_operator"
149			[(zero_extract:QHSI (match_operand:QHSI 1 "register_operand" "r")
150					    (const_int 1)
151					    (match_operand 2 "const_int_operand" "n"))
152			 (const_int 0)])
153		      (label_ref (match_operand 0 "" ""))
154		      (pc)))]
155  "INTVAL (operands[2]) < 16"
156  "#"
157  "&& reload_completed"
158  [(set (reg:CCZ CC_REG)
159	(eq (zero_extract:QHSI (match_dup 1) (const_int 1) (match_dup 2))
160	    (const_int 0)))
161   (set (pc)
162	(if_then_else (match_op_dup 3 [(reg:CCZ CC_REG) (const_int 0)])
163		      (label_ref (match_dup 0))
164		      (pc)))])
165
166(define_insn_and_split ""
167  [(set (pc)
168	(if_then_else (match_operator 3 "eqne_operator"
169			[(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
170					  (const_int 1)
171					  (match_operand 2 "const_int_operand" "n"))
172			 (const_int 0)])
173		      (label_ref (match_operand 0 "" ""))
174		      (pc)))
175   (clobber (match_scratch:SI 4 "=&r"))]
176  "INTVAL (operands[2]) >= 16"
177  "#"
178  "&& reload_completed"
179  [(parallel [(set (match_dup 4)
180		   (ior:SI (and:SI (match_dup 4) (const_int -65536))
181			   (lshiftrt:SI (match_dup 1) (const_int 16))))
182	      (clobber (reg:CC CC_REG))])
183   (set (reg:CCZ CC_REG)
184	(eq (zero_extract:SI (match_dup 4) (const_int 1) (match_dup 2))
185	    (const_int 0)))
186   (set (pc)
187	(if_then_else (match_op_dup 3 [(reg:CCZ CC_REG) (const_int 0)])
188		      (label_ref (match_dup 0))
189		      (pc)))]
190  "operands[2] = GEN_INT (INTVAL (operands[2]) - 16);")
191
192;; Unconditional and other jump instructions.
193
194(define_insn "jump"
195  [(set (pc)
196	(label_ref (match_operand 0 "" "")))]
197  ""
198{
199  if (final_sequence != 0)
200    {
201      if (get_attr_length (insn) == 2)
202	return "bra/s	%l0";
203      else
204	{
205	  /* The branch isn't short enough to use bra/s.  Output the
206	     branch and delay slot in their normal order.
207
208	     If this is a backward branch, it will now be branching two
209	     bytes further than previously thought.  The length-based
210	     test for bra vs. jump is very conservative though, so the
211	     branch will still be within range.  */
212	  rtx_sequence *seq;
213	  int seen;
214
215	  seq = final_sequence;
216	  final_sequence = 0;
217	  final_scan_insn (seq->insn (1), asm_out_file, optimize, 1, & seen);
218	  final_scan_insn (seq->insn (0), asm_out_file, optimize, 1, & seen);
219	  seq->insn (1)->set_deleted ();
220	  return "";
221	}
222    }
223  else if (get_attr_length (insn) == 2)
224    return "bra	%l0";
225  else if (get_attr_length (insn) == 4)
226    return "bra	%l0:16";
227  else
228    return "jmp	@%l0";
229}
230  [(set_attr "type" "branch")
231   (set (attr "delay_slot")
232	(if_then_else (match_test "TARGET_H8300SX")
233		      (const_string "jump")
234		      (const_string "none")))])
235
236;; This is a define expand, because pointers may be either 16 or 32 bits.
237
238(define_expand "tablejump"
239  [(parallel [(set (pc) (match_operand 0 "register_operand" ""))
240	      (use (label_ref (match_operand 1 "" "")))])]
241  ""
242  "")
243
244(define_insn "tablejump<mode>"
245  [(set (pc) (match_operand:P 0 "register_operand" "r"))
246   (use (label_ref (match_operand 1 "" "")))]
247  ""
248  {
249    if (<MODE>mode == E_HImode)
250      return "jmp	@%0";
251    if (<MODE>mode == E_SImode)
252      return "jmp	@%S0";
253    abort ();
254  }
255  [(set_attr "length" "2")])
256
257;; This is a define expand, because pointers may be either 16 or 32 bits.
258
259(define_expand "indirect_jump"
260  [(set (pc) (match_operand 0 "jump_address_operand" ""))]
261  ""
262  "")
263
264(define_insn "*indirect_jump_<mode>"
265  [(set (pc) (match_operand:P 0 "jump_address_operand" "Vr"))]
266  ""
267  {
268    if (<MODE>mode == E_HImode)
269      return "jmp	@%0";
270    if (<MODE>mode == E_SImode)
271      return "jmp	@%S0";
272    abort ();
273  }
274  [(set_attr "length" "2")])
275
276;; Call subroutine with no return value.
277
278;; ??? Even though we use HImode here, this works on the H8/300H and H8S.
279
280(define_expand "call"
281  [(call (match_operand:QI 0 "call_expander_operand" "")
282	 (match_operand 1 "general_operand" ""))]
283  ""
284  {
285    if (!register_operand (XEXP (operands[0], 0), Pmode)
286	&& GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
287      XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
288  })
289
290(define_insn "call_insn_<mode>"
291  [(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
292	         (match_operand:P 1 "general_operand" "g"))]
293  "!SIBLING_CALL_P (insn)"
294{
295  rtx xoperands[1];
296  xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
297  gcc_assert (GET_MODE (operands[0]) == Pmode);
298  if (GET_CODE (XEXP (xoperands[0], 0)) == SYMBOL_REF
299      && (SYMBOL_REF_FLAGS (XEXP (xoperands[0], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
300    output_asm_insn ("jsr\\t@%0:8", xoperands);
301  else
302    output_asm_insn ("jsr\\t%0", xoperands);
303  return "";
304}
305  [(set_attr "type" "call")
306   (set (attr "length")
307	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
308		      (const_int 2)
309		      (const_int 4)))])
310
311;; Call subroutine, returning value in operand 0
312;; (which must be a hard register).
313
314;; ??? Even though we use HImode here, this works on the H8/300H and H8S.
315
316(define_expand "call_value"
317  [(set (match_operand 0 "" "")
318	(call (match_operand:QI 1 "call_expander_operand" "")
319	      (match_operand 2 "general_operand" "")))]
320  ""
321  {
322    if (!register_operand (XEXP (operands[1], 0), Pmode)
323	&& GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
324      XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
325  })
326
327(define_insn "call_value_insn_<mode>"
328  [(set (match_operand 0 "" "=r")
329	(call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
330		      (match_operand:P 2 "general_operand" "g")))]
331  "!SIBLING_CALL_P (insn)"
332{
333  rtx xoperands[2];
334  gcc_assert (GET_MODE (operands[1]) == Pmode);
335  xoperands[0] = operands[0];
336  xoperands[1] = gen_rtx_MEM (QImode, operands[1]);
337  if (GET_CODE (XEXP (xoperands[1], 0)) == SYMBOL_REF
338      && (SYMBOL_REF_FLAGS (XEXP (xoperands[1], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
339    output_asm_insn ("jsr\\t@%1:8", xoperands);
340  else
341    output_asm_insn ("jsr\\t%1", xoperands);
342  return "";
343}
344  [(set_attr "type" "call")
345   (set (attr "length")
346	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
347		      (const_int 2)
348		      (const_int 4)))])
349
350(define_expand "sibcall"
351  [(call (match_operand:QI 0 "call_expander_operand" "")
352	 (match_operand 1 "general_operand" ""))]
353  ""
354  {
355    if (!register_operand (XEXP (operands[0], 0), Pmode)
356	&& GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
357      XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
358  })
359
360(define_insn "sibcall_insn_<mode>"
361  [(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
362	         (match_operand:P 1 "general_operand" "g"))]
363  "SIBLING_CALL_P (insn)"
364{
365  rtx xoperands[1];
366  xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
367  gcc_assert (GET_MODE (operands[0]) == Pmode);
368  if (GET_CODE (XEXP (xoperands[0], 0)) == SYMBOL_REF
369      && (SYMBOL_REF_FLAGS (XEXP (xoperands[0], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
370    output_asm_insn ("jmp\\t@%0:8", xoperands);
371  else
372    output_asm_insn ("jmp\\t%0", xoperands);
373  return "";
374}
375  [(set_attr "type" "call")
376   (set (attr "length")
377	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
378		      (const_int 2)
379		      (const_int 4)))])
380
381;; Call subroutine, returning value in operand 0
382;; (which must be a hard register).
383
384;; ??? Even though we use HImode here, this works on the H8/300H and H8S.
385
386(define_expand "sibcall_value"
387  [(set (match_operand 0 "" "")
388	(call (match_operand:QI 1 "call_expander_operand" "")
389	      (match_operand 2 "general_operand" "")))]
390  ""
391  {
392    if (!register_operand (XEXP (operands[1], 0), Pmode)
393	&& GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
394      XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
395  })
396
397(define_insn "sibcall_value_insn_<mode>"
398  [(set (match_operand 0 "" "=r")
399	(call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
400		      (match_operand:P 2 "general_operand" "g")))]
401  "SIBLING_CALL_P (insn)"
402{
403  rtx xoperands[2];
404  gcc_assert (GET_MODE (operands[1]) == Pmode);
405  xoperands[0] = operands[0];
406  xoperands[1] = gen_rtx_MEM (QImode, operands[1]);
407  if (GET_CODE (XEXP (xoperands[1], 0)) == SYMBOL_REF
408      && (SYMBOL_REF_FLAGS (XEXP (xoperands[1], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
409    output_asm_insn ("jmp\\t@%1:8", xoperands);
410  else
411    output_asm_insn ("jmp\\t%1", xoperands);
412  return "";
413}
414  [(set_attr "type" "call")
415   (set (attr "length")
416	(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
417		      (const_int 2)
418		      (const_int 4)))])
419
420