]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/i370/i370.c
PR c++/17413
[thirdparty/gcc.git] / gcc / config / i370 / i370.c
1 /* Subroutines for insn-output.c for System/370.
2 Copyright (C) 1989, 1993, 1995, 1997, 1998, 1999, 2000, 2002
3 Free Software Foundation, Inc.
4 Contributed by Jan Stein (jan@cd.chalmers.se).
5 Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
6 Hacked for Linux-ELF/390 by Linas Vepstas (linas@linas.org)
7
8 This file is part of GCC.
9
10 GCC is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GCC is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING. If not, write to
22 the Free Software Foundation, 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tm.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "regs.h"
32 #include "hard-reg-set.h"
33 #include "real.h"
34 #include "insn-config.h"
35 #include "conditions.h"
36 #include "output.h"
37 #include "insn-attr.h"
38 #include "function.h"
39 #include "expr.h"
40 #include "flags.h"
41 #include "recog.h"
42 #include "toplev.h"
43 #include "cpplib.h"
44 #include "tm_p.h"
45 #include "target.h"
46 #include "target-def.h"
47
48 extern FILE *asm_out_file;
49
50 /* Label node. This structure is used to keep track of labels
51 on the various pages in the current routine.
52 The label_id is the numeric ID of the label,
53 The label_page is the page on which it actually appears,
54 The first_ref_page is the page on which the true first ref appears.
55 The label_addr is an estimate of its location in the current routine,
56 The label_first & last_ref are estimates of where the earliest and
57 latest references to this label occur. */
58
59 typedef struct label_node
60 {
61 struct label_node *label_next;
62 int label_id;
63 int label_page;
64 int first_ref_page;
65
66 int label_addr;
67 int label_first_ref;
68 int label_last_ref;
69 }
70 label_node_t;
71
72 /* Is 1 when a label has been generated and the base register must be reloaded. */
73 int mvs_need_base_reload = 0;
74
75 /* Current function starting base page. */
76 int function_base_page;
77
78 /* Length of the current page code. */
79 int mvs_page_code;
80
81 /* Length of the current page literals. */
82 int mvs_page_lit;
83
84 /* Current function name. */
85 char *mvs_function_name = 0;
86
87 /* Current function name length. */
88 size_t mvs_function_name_length = 0;
89
90 /* Page number for multi-page functions. */
91 int mvs_page_num = 0;
92
93 /* Label node list anchor. */
94 static label_node_t *label_anchor = 0;
95
96 /* Label node free list anchor. */
97 static label_node_t *free_anchor = 0;
98
99 /* Assembler source file descriptor. */
100 static FILE *assembler_source = 0;
101
102 static label_node_t * mvs_get_label (int);
103 static void i370_label_scan (void);
104 #ifdef TARGET_HLASM
105 static bool i370_hlasm_assemble_integer (rtx, unsigned int, int);
106 static void i370_globalize_label (FILE *, const char *);
107 #endif
108 static void i370_output_function_prologue (FILE *, HOST_WIDE_INT);
109 static void i370_output_function_epilogue (FILE *, HOST_WIDE_INT);
110 static void i370_file_start (void);
111 static void i370_file_end (void);
112
113 #ifdef LONGEXTERNAL
114 static int mvs_hash_alias (const char *);
115 #endif
116 static void i370_internal_label (FILE *, const char *, unsigned long);
117 static bool i370_rtx_costs (rtx, int, int, int *);
118
119 /* ===================================================== */
120 /* defines and functions specific to the HLASM assembler */
121 #ifdef TARGET_HLASM
122
123 #define MVS_HASH_PRIME 999983
124 #if HOST_CHARSET == HOST_CHARSET_EBCDIC
125 #define MVS_SET_SIZE 256
126 #else
127 #define MVS_SET_SIZE 128
128 #endif
129
130 #ifndef MAX_MVS_LABEL_SIZE
131 #define MAX_MVS_LABEL_SIZE 8
132 #endif
133
134 #define MAX_LONG_LABEL_SIZE 255
135
136 /* Alias node, this structure is used to keep track of aliases to external
137 variables. The IBM assembler allows an alias to an external name
138 that is longer that 8 characters; but only once per assembly.
139 Also, this structure stores the #pragma map info. */
140 typedef struct alias_node
141 {
142 struct alias_node *alias_next;
143 int alias_emitted;
144 char alias_name [MAX_MVS_LABEL_SIZE + 1];
145 char real_name [MAX_LONG_LABEL_SIZE + 1];
146 }
147 alias_node_t;
148
149 /* Alias node list anchor. */
150 static alias_node_t *alias_anchor = 0;
151
152 /* Define the length of the internal MVS function table. */
153 #define MVS_FUNCTION_TABLE_LENGTH 32
154
155 /* C/370 internal function table. These functions use non-standard linkage
156 and must handled in a special manner. */
157 static const char *const mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] =
158 {
159 #if HOST_CHARSET == HOST_CHARSET_EBCDIC /* Changed for EBCDIC collating sequence */
160 "ceil", "edc_acos", "edc_asin", "edc_atan", "edc_ata2", "edc_cos",
161 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
162 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
163 "fabs", "floor", "fmod", "frexp", "hypot", "jn",
164 "j0", "j1", "ldexp", "modf", "pow", "yn",
165 "y0", "y1"
166 #else
167 "ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
168 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
169 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
170 "fabs", "floor", "fmod", "frexp", "hypot", "j0",
171 "j1", "jn", "ldexp", "modf", "pow", "y0",
172 "y1", "yn"
173 #endif
174 };
175
176 #endif /* TARGET_HLASM */
177 /* ===================================================== */
178
179 \f
180 /* Initialize the GCC target structure. */
181 #ifdef TARGET_HLASM
182 #undef TARGET_ASM_BYTE_OP
183 #define TARGET_ASM_BYTE_OP NULL
184 #undef TARGET_ASM_ALIGNED_HI_OP
185 #define TARGET_ASM_ALIGNED_HI_OP NULL
186 #undef TARGET_ASM_ALIGNED_SI_OP
187 #define TARGET_ASM_ALIGNED_SI_OP NULL
188 #undef TARGET_ASM_INTEGER
189 #define TARGET_ASM_INTEGER i370_hlasm_assemble_integer
190 #undef TARGET_ASM_GLOBALIZE_LABEL
191 #define TARGET_ASM_GLOBALIZE_LABEL i370_globalize_label
192 #endif
193
194 #undef TARGET_ASM_FUNCTION_PROLOGUE
195 #define TARGET_ASM_FUNCTION_PROLOGUE i370_output_function_prologue
196 #undef TARGET_ASM_FUNCTION_EPILOGUE
197 #define TARGET_ASM_FUNCTION_EPILOGUE i370_output_function_epilogue
198 #undef TARGET_ASM_FILE_START
199 #define TARGET_ASM_FILE_START i370_file_start
200 #undef TARGET_ASM_FILE_END
201 #define TARGET_ASM_FILE_END i370_file_end
202 #undef TARGET_ASM_INTERNAL_LABEL
203 #define TARGET_ASM_INTERNAL_LABEL i370_internal_label
204 #undef TARGET_RTX_COSTS
205 #define TARGET_RTX_COSTS i370_rtx_costs
206
207 struct gcc_target targetm = TARGET_INITIALIZER;
208 \f
209 /* Set global variables as needed for the options enabled. */
210
211 void
212 override_options ()
213 {
214 /* We're 370 floating point, not IEEE floating point. */
215 memset (real_format_for_mode, 0, sizeof real_format_for_mode);
216 REAL_MODE_FORMAT (SFmode) = &i370_single_format;
217 REAL_MODE_FORMAT (DFmode) = &i370_double_format;
218 }
219
220 /* ===================================================== */
221 /* The following three routines are used to determine whther
222 forward branch is on this page, or is a far jump. We use
223 the "length" attr on an insn [(set_atter "length" "4")]
224 to store the largest possible code length that insn
225 could have. This gives us a hint of the address of a
226 branch destination, and from that, we can work out
227 the length of the jump, and whether its on page or not.
228 */
229
230 /* Return the destination address of a branch. */
231
232 int
233 i370_branch_dest (branch)
234 rtx branch;
235 {
236 rtx dest = SET_SRC (PATTERN (branch));
237 int dest_uid;
238 int dest_addr;
239
240 /* first, compute the estimated address of the branch target */
241 if (GET_CODE (dest) == IF_THEN_ELSE)
242 dest = XEXP (dest, 1);
243 dest = XEXP (dest, 0);
244 dest_uid = INSN_UID (dest);
245 dest_addr = INSN_ADDRESSES (dest_uid);
246
247 /* next, record the address of this insn as the true addr of first ref */
248 {
249 label_node_t *lp;
250 rtx label = JUMP_LABEL (branch);
251 int labelno = CODE_LABEL_NUMBER (label);
252
253 if (!label || CODE_LABEL != GET_CODE (label)) abort ();
254
255 lp = mvs_get_label (labelno);
256 if (-1 == lp -> first_ref_page) lp->first_ref_page = mvs_page_num;
257 }
258 return dest_addr;
259 }
260
261 int
262 i370_branch_length (insn)
263 rtx insn;
264 {
265 int here, there;
266 here = INSN_ADDRESSES (INSN_UID (insn));
267 there = i370_branch_dest (insn);
268 return (there - here);
269 }
270
271
272 int
273 i370_short_branch (insn)
274 rtx insn;
275 {
276 int base_offset;
277
278 base_offset = i370_branch_length(insn);
279 if (0 > base_offset)
280 {
281 base_offset += mvs_page_code;
282 }
283 else
284 {
285 /* avoid bumping into lit pool; use 2x to estimate max possible lits */
286 base_offset *= 2;
287 base_offset += mvs_page_code + mvs_page_lit;
288 }
289
290 /* make a conservative estimate of room left on page */
291 if ((4060 >base_offset) && ( 0 < base_offset)) return 1;
292 return 0;
293 }
294
295 /* The i370_label_scan() routine is supposed to loop over
296 all labels and label references in a compilation unit,
297 and determine whether all label refs appear on the same
298 code page as the label. If they do, then we can avoid
299 a reload of the base register for that label.
300
301 Note that the instruction addresses used here are only
302 approximate, and make the sizes of the jumps appear
303 farther apart then they will actually be. This makes
304 this code far more conservative than it needs to be.
305 */
306
307 #define I370_RECORD_LABEL_REF(label,addr) { \
308 label_node_t *lp; \
309 int labelno = CODE_LABEL_NUMBER (label); \
310 lp = mvs_get_label (labelno); \
311 if (addr < lp -> label_first_ref) lp->label_first_ref = addr; \
312 if (addr > lp -> label_last_ref) lp->label_last_ref = addr; \
313 }
314
315 static void
316 i370_label_scan ()
317 {
318 rtx insn;
319 label_node_t *lp;
320 int tablejump_offset = 0;
321
322 for (insn = get_insns(); insn; insn = NEXT_INSN(insn))
323 {
324 int here = INSN_ADDRESSES (INSN_UID (insn));
325 enum rtx_code code = GET_CODE(insn);
326
327 /* ??? adjust for tables embedded in the .text section that
328 * the compiler didn't take into account */
329 here += tablejump_offset;
330 INSN_ADDRESSES (INSN_UID (insn)) = here;
331
332 /* check to see if this insn is a label ... */
333 if (CODE_LABEL == code)
334 {
335 int labelno = CODE_LABEL_NUMBER (insn);
336
337 lp = mvs_get_label (labelno);
338 lp -> label_addr = here;
339 #if 0
340 /* Supposedly, labels are supposed to have circular
341 lists of label-refs that reference them,
342 setup in flow.c, but this does not appear to be the case. */
343 rtx labelref = LABEL_REFS (insn);
344 rtx ref = labelref;
345 do
346 {
347 rtx linsn = CONTAINING_INSN(ref);
348 ref = LABEL_NEXTREF(ref);
349 } while (ref && (ref != labelref));
350 #endif
351 }
352 else
353 if (JUMP_INSN == code)
354 {
355 rtx label = JUMP_LABEL (insn);
356
357 /* If there is no label for this jump, then this
358 had better be a ADDR_VEC or an ADDR_DIFF_VEC
359 and there had better be a vector of labels. */
360 if (!label)
361 {
362 int j;
363 rtx body = PATTERN (insn);
364 if (ADDR_VEC == GET_CODE(body))
365 {
366 for (j=0; j < XVECLEN (body, 0); j++)
367 {
368 rtx lref = XVECEXP (body, 0, j);
369 if (LABEL_REF != GET_CODE (lref)) abort ();
370 label = XEXP (lref,0);
371 if (CODE_LABEL != GET_CODE (label)) abort ();
372 tablejump_offset += 4;
373 here += 4;
374 I370_RECORD_LABEL_REF(label,here);
375 }
376 /* finished with the vector go do next insn */
377 continue;
378 }
379 else
380 if (ADDR_DIFF_VEC == GET_CODE(body))
381 {
382 /* XXX hack alert.
383 Right now, we leave this as a no-op, but strictly speaking,
384 this is incorrect. It is possible that a table-jump
385 driven off of a relative address could take us off-page,
386 to a place where we need to reload the base reg. So really,
387 we need to examing both labels, and compare thier values
388 to the current basereg value.
389
390 More generally, this brings up a troubling issue overall:
391 what happens if a tablejump is split across two pages? I do
392 not beleive that this case is handled correctly at all, and
393 can only lead to horrible results if this were to occur.
394
395 However, the current situation is not any worse than it was
396 last week, and so we punt for now. */
397
398 debug_rtx (insn);
399 for (j=0; j < XVECLEN (body, 0); j++)
400 {
401 }
402 /* finished with the vector go do next insn */
403 continue;
404 }
405 else
406 {
407 /* XXX hack alert.
408 Compiling the exception handling (L_eh) in libgcc2.a will trip
409 up right here, with something that looks like
410 (set (pc) (mem:SI (plus:SI (reg/v:SI 1 r1) (const_int 4))))
411 {indirect_jump}
412 I'm not sure of what leads up to this, but it looks like
413 the makings of a long jump which will surely get us into trouble
414 because the base & page registers don't get reloaded. For now
415 I'm not sure of what to do ... again we punt ... we are not worse
416 off than yesterday. */
417
418 /* print_rtl_single (stdout, insn); */
419 debug_rtx (insn);
420 /* abort(); */
421 continue;
422 }
423 }
424 else
425 {
426 /* At this point, this jump_insn had better be a plain-old
427 ordinary one, grap the label id and go */
428 if (CODE_LABEL != GET_CODE (label)) abort ();
429 I370_RECORD_LABEL_REF(label,here);
430 }
431 }
432
433 /* Sometimes, we take addresses of labels and use them
434 as instruction operands ... these show up as REG_NOTES */
435 else
436 if (INSN == code)
437 {
438 if ('i' == GET_RTX_CLASS (code))
439 {
440 rtx note;
441 for (note = REG_NOTES (insn); note; note = XEXP(note,1))
442 {
443 if (REG_LABEL == REG_NOTE_KIND(note))
444 {
445 rtx label = XEXP (note,0);
446 if (!label || CODE_LABEL != GET_CODE (label)) abort ();
447
448 I370_RECORD_LABEL_REF(label,here);
449 }
450 }
451 }
452 }
453 }
454 }
455
456 /* ===================================================== */
457
458 /* Emit reload of base register if indicated. This is to eliminate multiple
459 reloads when several labels are generated pointing to the same place
460 in the code.
461
462 The page table is written at the end of the function.
463 The entries in the page table look like
464 .LPGT0: // PGT0 EQU *
465 .long .LPG0 // DC A(PG0)
466 .long .LPG1 // DC A(PG1)
467 while the prologue generates
468 L r4,=A(.LPGT0)
469
470 Note that this paging scheme breaks down if a single subroutine
471 has more than about 10MB of code in it ... as long as humans write
472 code, this shouldn't be a problem ...
473 */
474
475 void
476 check_label_emit ()
477 {
478 if (mvs_need_base_reload)
479 {
480 mvs_need_base_reload = 0;
481
482 mvs_page_code += 4;
483 fprintf (assembler_source, "\tL\t%d,%d(,%d)\n",
484 BASE_REGISTER, (mvs_page_num - function_base_page) * 4,
485 PAGE_REGISTER);
486 }
487 }
488
489 /* Add the label to the current page label list. If a free element is available
490 it will be used for the new label. Otherwise, a label element will be
491 allocated from memory.
492 ID is the label number of the label being added to the list. */
493
494 static label_node_t *
495 mvs_get_label (id)
496 int id;
497 {
498 label_node_t *lp;
499
500 /* first, lets see if we already go one, if so, use that. */
501 for (lp = label_anchor; lp; lp = lp->label_next)
502 {
503 if (lp->label_id == id) return lp;
504 }
505
506 /* not found, get a new one */
507 if (free_anchor)
508 {
509 lp = free_anchor;
510 free_anchor = lp->label_next;
511 }
512 else
513 {
514 lp = (label_node_t *) xmalloc (sizeof (label_node_t));
515 }
516
517 /* initialize for new label */
518 lp->label_id = id;
519 lp->label_page = -1;
520 lp->label_next = label_anchor;
521 lp->label_first_ref = 2000123123;
522 lp->label_last_ref = -1;
523 lp->label_addr = -1;
524 lp->first_ref_page = -1;
525 label_anchor = lp;
526
527 return lp;
528 }
529
530 void
531 mvs_add_label (id)
532 int id;
533 {
534 label_node_t *lp;
535 int fwd_distance;
536
537 lp = mvs_get_label (id);
538 lp->label_page = mvs_page_num;
539
540 /* OK, we just saw the label. Determine if this label
541 * needs a reload of the base register */
542 if ((-1 != lp->first_ref_page) &&
543 (lp->first_ref_page != mvs_page_num))
544 {
545 /* Yep; the first label_ref was on a different page. */
546 mvs_need_base_reload ++;
547 return;
548 }
549
550 /* Hmm. Try to see if the estimated address of the last
551 label_ref is on the current page. If it is, then we
552 don't need a base reg reload. Note that this estimate
553 is very conservatively handled; we'll tend to have
554 a good bit more reloads than actually needed. Someday,
555 we should tighten the estimates (which are driven by
556 the (set_att "length") insn attibute.
557
558 Currently, we estimate that number of page literals
559 same as number of insns, which is a vast overestimate,
560 esp that the estimate of each insn size is its max size. */
561
562 /* if latest ref comes before label, we are clear */
563 if (lp->label_last_ref < lp->label_addr) return;
564
565 fwd_distance = lp->label_last_ref - lp->label_addr;
566
567 if (mvs_page_code + 2 * fwd_distance + mvs_page_lit < 4060) return;
568
569 mvs_need_base_reload ++;
570 }
571
572 /* Check to see if the label is in the list and in the current
573 page. If not found, we have to make worst case assumption
574 that label will be on a different page, and thus will have to
575 generate a load and branch on register. This is rather
576 ugly for forward-jumps, but what can we do? For backward
577 jumps on the same page we can branch directly to address.
578 ID is the label number of the label being checked. */
579
580 int
581 mvs_check_label (id)
582 int id;
583 {
584 label_node_t *lp;
585
586 for (lp = label_anchor; lp; lp = lp->label_next)
587 {
588 if (lp->label_id == id)
589 {
590 if (lp->label_page == mvs_page_num)
591 {
592 return 1;
593 }
594 else
595 {
596 return 0;
597 }
598 }
599 }
600 return 0;
601 }
602
603 /* Get the page on which the label sits. This will be used to
604 determine is a register reload is really needed. */
605
606 #if 0
607 int
608 mvs_get_label_page(int id)
609 {
610 label_node_t *lp;
611
612 for (lp = label_anchor; lp; lp = lp->label_next)
613 {
614 if (lp->label_id == id)
615 return lp->label_page;
616 }
617 return -1;
618 }
619 #endif
620
621 /* The label list for the current page freed by linking the list onto the free
622 label element chain. */
623
624 void
625 mvs_free_label_list ()
626 {
627
628 if (label_anchor)
629 {
630 label_node_t *last_lp = label_anchor;
631 while (last_lp->label_next) last_lp = last_lp->label_next;
632 last_lp->label_next = free_anchor;
633 free_anchor = label_anchor;
634 }
635 label_anchor = 0;
636 }
637
638 /* ====================================================================== */
639 /* If the page size limit is reached a new code page is started, and the base
640 register is set to it. This page break point is counted conservatively,
641 most literals that have the same value are collapsed by the assembler.
642 True is returned when a new page is started.
643 FILE is the assembler output file descriptor.
644 CODE is the length, in bytes, of the instruction to be emitted.
645 LIT is the length of the literal to be emitted. */
646
647 #ifdef TARGET_HLASM
648 int
649 mvs_check_page (file, code, lit)
650 FILE *file;
651 int code, lit;
652 {
653 if (file)
654 assembler_source = file;
655
656 if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH)
657 {
658 fprintf (assembler_source, "\tB\tPGE%d\n", mvs_page_num);
659 fprintf (assembler_source, "\tDS\t0F\n");
660 fprintf (assembler_source, "\tLTORG\n");
661 fprintf (assembler_source, "\tDS\t0F\n");
662 fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num);
663 fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER);
664 mvs_page_num++;
665 /* Safe to use BASR not BALR, since we are
666 * not switching addressing mode here ... */
667 fprintf (assembler_source, "\tBASR\t%d,0\n", BASE_REGISTER);
668 fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num);
669 fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER);
670 mvs_page_code = code;
671 mvs_page_lit = lit;
672 return 1;
673 }
674 mvs_page_code += code;
675 mvs_page_lit += lit;
676 return 0;
677 }
678 #endif /* TARGET_HLASM */
679
680
681 #ifdef TARGET_ELF_ABI
682 int
683 mvs_check_page (file, code, lit)
684 FILE *file;
685 int code, lit;
686 {
687 if (file)
688 assembler_source = file;
689
690 if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH)
691 {
692 /* hop past the literal pool */
693 fprintf (assembler_source, "\tB\t.LPGE%d\n", mvs_page_num);
694
695 /* dump the literal pool. The .baligns are optional, since
696 * ltorg will align to the size of the largest literal
697 * (which is possibly 8 bytes) */
698 fprintf (assembler_source, "\t.balign\t4\n");
699 fprintf (assembler_source, "\t.LTORG\n");
700 fprintf (assembler_source, "\t.balign\t4\n");
701
702 /* we continue execution here ... */
703 fprintf (assembler_source, ".LPGE%d:\n", mvs_page_num);
704 fprintf (assembler_source, "\t.DROP\t%d\n", BASE_REGISTER);
705 mvs_page_num++;
706
707 /* BASR puts the contents of the PSW into r3
708 * that is, r3 will be loaded with the address of "." */
709 fprintf (assembler_source, "\tBASR\tr%d,0\n", BASE_REGISTER);
710 fprintf (assembler_source, ".LPG%d:\n", mvs_page_num);
711 fprintf (assembler_source, "\t.USING\t.,r%d\n", BASE_REGISTER);
712 mvs_page_code = code;
713 mvs_page_lit = lit;
714 return 1;
715 }
716 mvs_page_code += code;
717 mvs_page_lit += lit;
718 return 0;
719 }
720 #endif /* TARGET_ELF_ABI */
721
722 /* ===================================================== */
723 /* defines and functions specific to the HLASM assembler */
724 #ifdef TARGET_HLASM
725
726 /* Check for C/370 runtime function, they don't use standard calling
727 conventions. True is returned if the function is in the table.
728 NAME is the name of the current function. */
729
730 int
731 mvs_function_check (name)
732 const char *name;
733 {
734 int lower, middle, upper;
735 int i;
736
737 lower = 0;
738 upper = MVS_FUNCTION_TABLE_LENGTH - 1;
739 while (lower <= upper)
740 {
741 middle = (lower + upper) / 2;
742 i = strcmp (name, mvs_function_table[middle]);
743 if (i == 0)
744 return 1;
745 if (i < 0)
746 upper = middle - 1;
747 else
748 lower = middle + 1;
749 }
750 return 0;
751 }
752
753 /* Generate a hash for a given key. */
754
755 #ifdef LONGEXTERNAL
756 static int
757 mvs_hash_alias (key)
758 const char *key;
759 {
760 int h;
761 int i;
762 int l = strlen (key);
763
764 h = key[0];
765 for (i = 1; i < l; i++)
766 h = ((h * MVS_SET_SIZE) + key[i]) % MVS_HASH_PRIME;
767 return (h);
768 }
769 #endif
770
771 /* Add the alias to the current alias list. */
772
773 void
774 mvs_add_alias (realname, aliasname, emitted)
775 const char *realname;
776 const char *aliasname;
777 int emitted;
778 {
779 alias_node_t *ap;
780
781 ap = (alias_node_t *) xmalloc (sizeof (alias_node_t));
782 if (strlen (realname) > MAX_LONG_LABEL_SIZE)
783 {
784 warning ("real name is too long - alias ignored");
785 return;
786 }
787 if (strlen (aliasname) > MAX_MVS_LABEL_SIZE)
788 {
789 warning ("alias name is too long - alias ignored");
790 return;
791 }
792
793 strcpy (ap->real_name, realname);
794 strcpy (ap->alias_name, aliasname);
795 ap->alias_emitted = emitted;
796 ap->alias_next = alias_anchor;
797 alias_anchor = ap;
798 }
799
800 /* Check to see if the name needs aliasing. ie. the name is either:
801 1. Longer than 8 characters
802 2. Contains an underscore
803 3. Is mixed case */
804
805 int
806 mvs_need_alias (realname)
807 const char *realname;
808 {
809 int i, j = strlen (realname);
810
811 if (mvs_function_check (realname))
812 return 0;
813 #if 0
814 if (!strcmp (realname, "gccmain"))
815 return 0;
816 if (!strcmp (realname, "main"))
817 return 0;
818 #endif
819 if (j > MAX_MVS_LABEL_SIZE)
820 return 1;
821 if (strchr (realname, '_') != 0)
822 return 1;
823 if (ISUPPER (realname[0]))
824 {
825 for (i = 1; i < j; i++)
826 {
827 if (ISLOWER (realname[i]))
828 return 1;
829 }
830 }
831 else
832 {
833 for (i = 1; i < j; i++)
834 {
835 if (ISUPPER (realname[i]))
836 return 1;
837 }
838 }
839
840 return 0;
841 }
842
843 /* Get the alias from the list.
844 If 1 is returned then it's in the alias list, 0 if it was not */
845
846 int
847 mvs_get_alias (realname, aliasname)
848 const char *realname;
849 char *aliasname;
850 {
851 #ifdef LONGEXTERNAL
852 alias_node_t *ap;
853
854 for (ap = alias_anchor; ap; ap = ap->alias_next)
855 {
856 if (!strcmp (ap->real_name, realname))
857 {
858 strcpy (aliasname, ap->alias_name);
859 return 1;
860 }
861 }
862 if (mvs_need_alias (realname))
863 {
864 char c1, c2;
865
866 c1 = realname[0];
867 c2 = realname[1];
868 if (ISLOWER (c1)) c1 = TOUPPER (c1);
869 else if (c1 == '_') c1 = 'A';
870 if (ISLOWER (c2)) c2 = TOUPPER (c2);
871 else if (c2 == '_' || c2 == '\0') c2 = '#';
872
873 sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname));
874 mvs_add_alias (realname, aliasname, 0);
875 return 1;
876 }
877 #else
878 if (strlen (realname) > MAX_MVS_LABEL_SIZE)
879 {
880 strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE);
881 aliasname[MAX_MVS_LABEL_SIZE] = '\0';
882 return 1;
883 }
884 #endif
885 return 0;
886 }
887
888 /* Check to see if the alias is in the list.
889 If 1 is returned then it's in the alias list, 2 it was emitted */
890
891 int
892 mvs_check_alias (realname, aliasname)
893 const char *realname;
894 char *aliasname;
895 {
896 #ifdef LONGEXTERNAL
897 alias_node_t *ap;
898
899 for (ap = alias_anchor; ap; ap = ap->alias_next)
900 {
901 if (!strcmp (ap->real_name, realname))
902 {
903 int rc = (ap->alias_emitted == 1) ? 1 : 2;
904 strcpy (aliasname, ap->alias_name);
905 ap->alias_emitted = 1;
906 return rc;
907 }
908 }
909 if (mvs_need_alias (realname))
910 {
911 char c1, c2;
912
913 c1 = realname[0];
914 c2 = realname[1];
915 if (ISLOWER (c1)) c1 = TOUPPER (c1);
916 else if (c1 == '_') c1 = 'A';
917 if (ISLOWER (c2)) c2 = TOUPPER (c2);
918 else if (c2 == '_' || c2 == '\0') c2 = '#';
919
920 sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname));
921 mvs_add_alias (realname, aliasname, 0);
922 alias_anchor->alias_emitted = 1;
923 return 2;
924 }
925 #else
926 if (strlen (realname) > MAX_MVS_LABEL_SIZE)
927 {
928 strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE);
929 aliasname[MAX_MVS_LABEL_SIZE] = '\0';
930 return 1;
931 }
932 #endif
933 return 0;
934 }
935
936 /* defines and functions specific to the HLASM assembler */
937 #endif /* TARGET_HLASM */
938 /* ===================================================== */
939 /* ===================================================== */
940 /* defines and functions specific to the gas assembler */
941 #ifdef TARGET_ELF_ABI
942
943 /* Check for C/370 runtime function, they don't use standard calling
944 conventions. True is returned if the function is in the table.
945 NAME is the name of the current function. */
946 /* no special calling conventions (yet ??) */
947
948 int
949 mvs_function_check (name)
950 const char *name ATTRIBUTE_UNUSED;
951 {
952 return 0;
953 }
954
955 #endif /* TARGET_ELF_ABI */
956 /* ===================================================== */
957
958
959 /* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
960 OP is the current operation.
961 MODE is the current operation mode. */
962
963 int
964 s_operand (op, mode)
965 register rtx op;
966 enum machine_mode mode;
967 {
968 extern int volatile_ok;
969 register enum rtx_code code = GET_CODE (op);
970
971 if (CONSTANT_ADDRESS_P (op))
972 return 1;
973 if (mode == VOIDmode || GET_MODE (op) != mode)
974 return 0;
975 if (code == MEM)
976 {
977 register rtx x = XEXP (op, 0);
978
979 if (!volatile_ok && op->volatil)
980 return 0;
981 if (REG_P (x) && REG_OK_FOR_BASE_P (x))
982 return 1;
983 if (GET_CODE (x) == PLUS
984 && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
985 && GET_CODE (XEXP (x, 1)) == CONST_INT
986 && (unsigned) INTVAL (XEXP (x, 1)) < 4096)
987 return 1;
988 }
989 return 0;
990 }
991
992
993 /* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
994 instruction.
995 OP is the current operation.
996 MODE is the current operation mode. */
997
998 int
999 r_or_s_operand (op, mode)
1000 register rtx op;
1001 enum machine_mode mode;
1002 {
1003 extern int volatile_ok;
1004 register enum rtx_code code = GET_CODE (op);
1005
1006 if (CONSTANT_ADDRESS_P (op))
1007 return 1;
1008 if (mode == VOIDmode || GET_MODE (op) != mode)
1009 return 0;
1010 if (code == REG)
1011 return 1;
1012 else if (code == MEM)
1013 {
1014 register rtx x = XEXP (op, 0);
1015
1016 if (!volatile_ok && op->volatil)
1017 return 0;
1018 if (REG_P (x) && REG_OK_FOR_BASE_P (x))
1019 return 1;
1020 if (GET_CODE (x) == PLUS
1021 && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
1022 && GET_CODE (XEXP (x, 1)) == CONST_INT
1023 && (unsigned) INTVAL (XEXP (x, 1)) < 4096)
1024 return 1;
1025 }
1026 return 0;
1027 }
1028
1029
1030 /* Some remarks about unsigned_jump_follows_p():
1031 gcc is built around the assumption that branches are signed
1032 or unsigned, whereas the 370 doesn't care; its the compares that
1033 are signed or unsigned. Thus, we need to somehow know if we
1034 need to do a signed or an unsigned compare, and we do this by
1035 looking ahead in the instruction sequence until we find a jump.
1036 We then note whether this jump is signed or unsigned, and do the
1037 compare appropriately. Note that we have to scan ahead indefinitley,
1038 as the gcc optimizer may insert any number of instructions between
1039 the compare and the jump.
1040
1041 Note that using conditional branch expanders seems to be be a more
1042 elegant/correct way of doing this. See, for instance, the Alpha
1043 cmpdi and bgt patterns. Note also that for the i370, various
1044 arithmetic insn's set the condition code as well.
1045
1046 The unsigned_jump_follows_p() routine returns a 1 if the next jump
1047 is unsigned. INSN is the current instruction. */
1048
1049 int
1050 unsigned_jump_follows_p (insn)
1051 register rtx insn;
1052 {
1053 rtx orig_insn = insn;
1054 while (1)
1055 {
1056 register rtx tmp_insn;
1057 enum rtx_code coda;
1058
1059 insn = NEXT_INSN (insn);
1060 if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn);
1061
1062 if (GET_CODE (insn) != JUMP_INSN) continue;
1063
1064 tmp_insn = XEXP (insn, 3);
1065 if (GET_CODE (tmp_insn) != SET) continue;
1066
1067 if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue;
1068
1069 tmp_insn = XEXP (tmp_insn, 1);
1070 if (GET_CODE (tmp_insn) != IF_THEN_ELSE) continue;
1071
1072 /* if we got to here, this instruction is a jump. Is it signed? */
1073 tmp_insn = XEXP (tmp_insn, 0);
1074 coda = GET_CODE (tmp_insn);
1075
1076 return coda != GE && coda != GT && coda != LE && coda != LT;
1077 }
1078 }
1079
1080 #ifdef TARGET_HLASM
1081
1082 /* Target hook for assembling integer objects. This version handles all
1083 objects when TARGET_HLASM is defined. */
1084
1085 static bool
1086 i370_hlasm_assemble_integer (x, size, aligned_p)
1087 rtx x;
1088 unsigned int size;
1089 int aligned_p;
1090 {
1091 const char *int_format = NULL;
1092
1093 if (aligned_p)
1094 switch (size)
1095 {
1096 case 1:
1097 int_format = "\tDC\tX'%02X'\n";
1098 break;
1099
1100 case 2:
1101 int_format = "\tDC\tX'%04X'\n";
1102 break;
1103
1104 case 4:
1105 if (GET_CODE (x) == CONST_INT)
1106 {
1107 fputs ("\tDC\tF'", asm_out_file);
1108 output_addr_const (asm_out_file, x);
1109 fputs ("'\n", asm_out_file);
1110 }
1111 else
1112 {
1113 fputs ("\tDC\tA(", asm_out_file);
1114 output_addr_const (asm_out_file, x);
1115 fputs (")\n", asm_out_file);
1116 }
1117 return true;
1118 }
1119
1120 if (int_format && GET_CODE (x) == CONST_INT)
1121 {
1122 fprintf (asm_out_file, int_format, INTVAL (x));
1123 return true;
1124 }
1125 return default_assemble_integer (x, size, aligned_p);
1126 }
1127
1128 /* Generate the assembly code for function entry. FILE is a stdio
1129 stream to output the code to. SIZE is an int: how many units of
1130 temporary storage to allocate.
1131
1132 Refer to the array `regs_ever_live' to determine which registers to
1133 save; `regs_ever_live[I]' is nonzero if register number I is ever
1134 used in the function. This function is responsible for knowing
1135 which registers should not be saved even if used. */
1136
1137 static void
1138 i370_output_function_prologue (f, l)
1139 FILE *f;
1140 HOST_WIDE_INT l;
1141 {
1142 #if MACROPROLOGUE == 1
1143 fprintf (f, "* Function %s prologue\n", mvs_function_name);
1144 fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
1145 STACK_POINTER_OFFSET + l - 120 +
1146 current_function_outgoing_args_size, BASE_REGISTER);
1147 #else /* MACROPROLOGUE != 1 */
1148 static int function_label_index = 1;
1149 static int function_first = 0;
1150 static int function_year, function_month, function_day;
1151 static int function_hour, function_minute, function_second;
1152 #if defined(LE370)
1153 if (!function_first)
1154 {
1155 struct tm *function_time;
1156 time_t lcltime;
1157 time (&lcltime);
1158 function_time = localtime (&lcltime);
1159 function_year = function_time->tm_year + 1900;
1160 function_month = function_time->tm_mon + 1;
1161 function_day = function_time->tm_mday;
1162 function_hour = function_time->tm_hour;
1163 function_minute = function_time->tm_min;
1164 function_second = function_time->tm_sec;
1165 }
1166 fprintf (f, "* Function %s prologue\n", mvs_function_name);
1167 fprintf (f, "FDSE%03d\tDSECT\n", function_label_index);
1168 fprintf (f, "\tDS\tD\n");
1169 fprintf (f, "\tDS\tCL(" HOST_WIDE_INT_PRINT_DEC ")\n",
1170 STACK_POINTER_OFFSET + l
1171 + current_function_outgoing_args_size);
1172 fprintf (f, "\tORG\tFDSE%03d\n", function_label_index);
1173 fprintf (f, "\tDS\tCL(120+8)\n");
1174 fprintf (f, "\tORG\n");
1175 fprintf (f, "\tDS\t0D\n");
1176 fprintf (f, "FDSL%03d\tEQU\t*-FDSE%03d-8\n", function_label_index,
1177 function_label_index);
1178 fprintf (f, "\tDS\t0H\n");
1179 assemble_name (f, mvs_function_name);
1180 fprintf (f, "\tCSECT\n");
1181 fprintf (f, "\tUSING\t*,15\n");
1182 fprintf (f, "\tB\tFENT%03d\n", function_label_index);
1183 fprintf (f, "\tDC\tAL1(FNAM%03d+4-*)\n", function_label_index);
1184 fprintf (f, "\tDC\tX'CE',X'A0',AL1(16)\n");
1185 fprintf (f, "\tDC\tAL4(FPPA%03d)\n", function_label_index);
1186 fprintf (f, "\tDC\tAL4(0)\n");
1187 fprintf (f, "\tDC\tAL4(FDSL%03d)\n", function_label_index);
1188 fprintf (f, "FNAM%03d\tEQU\t*\n", function_label_index);
1189 fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
1190 mvs_function_name);
1191 fprintf (f, "FPPA%03d\tDS\t0F\n", function_label_index);
1192 fprintf (f, "\tDC\tX'03',X'00',X'33',X'00'\n");
1193 fprintf (f, "\tDC\tV(CEESTART)\n");
1194 fprintf (f, "\tDC\tAL4(0)\n");
1195 fprintf (f, "\tDC\tAL4(FTIM%03d)\n", function_label_index);
1196 fprintf (f, "FTIM%03d\tDS\t0F\n", function_label_index);
1197 fprintf (f, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1198 function_year, function_month, function_day,
1199 function_hour, function_minute);
1200 fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
1201 fprintf (f, "FENT%03d\tDS\t0H\n", function_label_index);
1202 fprintf (f, "\tSTM\t14,12,12(13)\n");
1203 fprintf (f, "\tL\t2,76(,13)\n");
1204 fprintf (f, "\tL\t0,16(,15)\n");
1205 fprintf (f, "\tALR\t0,2\n");
1206 fprintf (f, "\tCL\t0,12(,12)\n");
1207 fprintf (f, "\tBNH\t*+10\n");
1208 fprintf (f, "\tL\t15,116(,12)\n");
1209 fprintf (f, "\tBALR\t14,15\n");
1210 fprintf (f, "\tL\t15,72(,13)\n");
1211 fprintf (f, "\tSTM\t15,0,72(2)\n");
1212 fprintf (f, "\tMVI\t0(2),X'10'\n");
1213 fprintf (f, "\tST\t2,8(,13)\n ");
1214 fprintf (f, "\tST\t13,4(,2)\n ");
1215 fprintf (f, "\tLR\t13,2\n");
1216 fprintf (f, "\tDROP\t15\n");
1217 fprintf (f, "\tBALR\t%d,0\n", BASE_REGISTER);
1218 fprintf (f, "\tUSING\t*,%d\n", BASE_REGISTER);
1219 function_first = 1;
1220 function_label_index ++;
1221 #else /* !LE370 */
1222 if (!function_first)
1223 {
1224 struct tm *function_time;
1225 time_t lcltime;
1226 time (&lcltime);
1227 function_time = localtime (&lcltime);
1228 function_year = function_time->tm_year + 1900;
1229 function_month = function_time->tm_mon + 1;
1230 function_day = function_time->tm_mday;
1231 function_hour = function_time->tm_hour;
1232 function_minute = function_time->tm_min;
1233 function_second = function_time->tm_sec;
1234 fprintf (f, "PPA2\tDS\t0F\n");
1235 fprintf (f, "\tDC\tX'03',X'00',X'33',X'00'\n");
1236 fprintf (f, "\tDC\tV(CEESTART),A(0)\n");
1237 fprintf (f, "\tDC\tA(CEETIMES)\n");
1238 fprintf (f, "CEETIMES\tDS\t0F\n");
1239 fprintf (f, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1240 function_year, function_month, function_day,
1241 function_hour, function_minute, function_second);
1242 fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
1243 }
1244 fprintf (f, "* Function %s prologue\n", mvs_function_name);
1245 fprintf (f, "FDSD%03d\tDSECT\n", function_label_index);
1246 fprintf (f, "\tDS\tD\n");
1247 fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l
1248 + current_function_outgoing_args_size);
1249 fprintf (f, "\tORG\tFDSD%03d\n", function_label_index);
1250 fprintf (f, "\tDS\tCL(120+8)\n");
1251 fprintf (f, "\tORG\n");
1252 fprintf (f, "\tDS\t0D\n");
1253 fprintf (f, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index,
1254 function_label_index);
1255 fprintf (f, "\tDS\t0H\n");
1256 assemble_name (f, mvs_function_name);
1257 fprintf (f, "\tCSECT\n");
1258 fprintf (f, "\tUSING\t*,15\n");
1259 fprintf (f, "\tB\tFPL%03d\n", function_label_index);
1260 fprintf (f, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index + 1);
1261 fprintf (f, "\tDC\tX'CE',X'A0',AL1(16)\n");
1262 fprintf (f, "\tDC\tAL4(PPA2)\n");
1263 fprintf (f, "\tDC\tAL4(0)\n");
1264 fprintf (f, "\tDC\tAL4(FDSL%03d)\n", function_label_index);
1265 fprintf (f, "FPL%03d\tEQU\t*\n", function_label_index + 1);
1266 fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
1267 mvs_function_name);
1268 fprintf (f, "FPL%03d\tDS\t0H\n", function_label_index);
1269 fprintf (f, "\tSTM\t14,12,12(13)\n");
1270 fprintf (f, "\tL\t2,76(,13)\n");
1271 fprintf (f, "\tL\t0,16(,15)\n");
1272 fprintf (f, "\tALR\t0,2\n");
1273 fprintf (f, "\tCL\t0,12(,12)\n");
1274 fprintf (f, "\tBNH\t*+10\n");
1275 fprintf (f, "\tL\t15,116(,12)\n");
1276 fprintf (f, "\tBALR\t14,15\n");
1277 fprintf (f, "\tL\t15,72(,13)\n");
1278 fprintf (f, "\tSTM\t15,0,72(2)\n");
1279 fprintf (f, "\tMVI\t0(2),X'10'\n");
1280 fprintf (f, "\tST\t2,8(,13)\n ");
1281 fprintf (f, "\tST\t13,4(,2)\n ");
1282 fprintf (f, "\tLR\t13,2\n");
1283 fprintf (f, "\tDROP\t15\n");
1284 fprintf (f, "\tBALR\t%d,0\n", BASE_REGISTER);
1285 fprintf (f, "\tUSING\t*,%d\n", BASE_REGISTER);
1286 function_first = 1;
1287 function_label_index += 2;
1288 #endif /* !LE370 */
1289 #endif /* MACROPROLOGUE */
1290 fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
1291 fprintf (f, "\tLR\t11,1\n");
1292 fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num);
1293 fprintf (f, "* Function %s code\n", mvs_function_name);
1294
1295 mvs_free_label_list ();
1296 mvs_page_code = 6;
1297 mvs_page_lit = 4;
1298 mvs_check_page (f, 0, 0);
1299 function_base_page = mvs_page_num;
1300
1301 /* find all labels in this routine */
1302 i370_label_scan ();
1303 }
1304
1305 static void
1306 i370_globalize_label (stream, name)
1307 FILE *stream;
1308 const char *name;
1309 {
1310 char temp[MAX_MVS_LABEL_SIZE + 1];
1311 if (mvs_check_alias (name, temp) == 2)
1312 fprintf (stream, "%s\tALIAS\tC'%s'\n", temp, name);
1313 fputs ("\tENTRY\t", stream);
1314 assemble_name (stream, name);
1315 putc ('\n', stream);
1316 }
1317 #endif /* TARGET_HLASM */
1318
1319
1320 #ifdef TARGET_ELF_ABI
1321 /*
1322 The 370_function_prolog() routine generates the current ELF ABI ES/390 prolog.
1323 It implements a stack that grows downward.
1324 It performs the following steps:
1325 -- saves the callers non-volatile registers on the callers stack.
1326 -- subtracts stackframe size from the stack pointer.
1327 -- stores backpointer to old caller stack.
1328
1329 XXX hack alert -- if the global var int leaf_function is nonzero,
1330 then this is a leaf, and it might be possible to optimize the prologue
1331 into doing even less, e.g. not grabbing a new stackframe or maybe just a
1332 partial stack frame.
1333
1334 XXX hack alert -- the current stack frame is bloated into twice the
1335 needed size by unused entries. These entries make it marginally
1336 compatible with MVS/OE/USS C environment, but really they're not used
1337 and could probably chopped out. Modifications to i370.md would be needed
1338 also, to quite using addresses 136, 140, etc.
1339 */
1340
1341 static void
1342 i370_output_function_prologue (f, frame_size)
1343 FILE *f;
1344 HOST_WIDE_INT frame_size;
1345 {
1346 static int function_label_index = 1;
1347 static int function_first = 0;
1348 int stackframe_size, aligned_size;
1349
1350 fprintf (f, "# Function prologue\n");
1351 /* define the stack, put it into its own data segment
1352 FDSE == Function Stack Entry
1353 FDSL == Function Stack Length */
1354 stackframe_size =
1355 STACK_POINTER_OFFSET + current_function_outgoing_args_size + frame_size;
1356 aligned_size = (stackframe_size + 7) >> 3;
1357 aligned_size <<= 3;
1358
1359 fprintf (f, "# arg_size=0x%x frame_size=" HOST_WIDE_INT_PRINT_HEX
1360 " aligned size=0x%x\n",
1361 current_function_outgoing_args_size, frame_size, aligned_size);
1362
1363 fprintf (f, "\t.using\t.,r15\n");
1364
1365 /* Branch to exectuable part of prologue. */
1366 fprintf (f, "\tB\t.LFENT%03d\n", function_label_index);
1367
1368 /* write the length of the stackframe */
1369 fprintf (f, "\t.long\t%d\n", aligned_size);
1370
1371 /* FENT == function prologue entry */
1372 fprintf (f, "\t.balign 2\n.LFENT%03d:\n",
1373 function_label_index);
1374
1375 /* store multiple registers 14,15,0,...12 at 12 bytes from sp */
1376 fprintf (f, "\tSTM\tr14,r12,12(sp)\n");
1377
1378 /* r3 == saved callee stack pointer */
1379 fprintf (f, "\tLR\tr3,sp\n");
1380
1381 /* 4(r15) == stackframe size */
1382 fprintf (f, "\tSL\tsp,4(,r15)\n");
1383
1384 /* r11 points to arg list in callers stackframe; was passed in r2 */
1385 fprintf (f, "\tLR\tr11,r2\n");
1386
1387 /* store callee stack pointer at 8(sp) */
1388 /* fprintf (f, "\tST\tsp,8(,r3)\n "); wasted cycles, no one uses this ... */
1389
1390 /* backchain -- store caller sp at 4(callee_sp) */
1391 fprintf (f, "\tST\tr3,4(,sp)\n ");
1392
1393 fprintf (f, "\t.drop\tr15\n");
1394 /* Place contents of the PSW into r3
1395 that is, place the address of "." into r3 */
1396 fprintf (f, "\tBASR\tr%d,0\n", BASE_REGISTER);
1397 fprintf (f, "\t.using\t.,r%d\n", BASE_REGISTER);
1398 function_first = 1;
1399 function_label_index ++;
1400
1401 fprintf (f, ".LPG%d:\n", mvs_page_num );
1402 fprintf (f, "\tL\tr%d,=A(.LPGT%d)\n", PAGE_REGISTER, mvs_page_num);
1403 fprintf (f, "# Function code\n");
1404
1405 mvs_free_label_list ();
1406 mvs_page_code = 6;
1407 mvs_page_lit = 4;
1408 mvs_check_page (f, 0, 0);
1409 function_base_page = mvs_page_num;
1410
1411 /* find all labels in this routine */
1412 i370_label_scan ();
1413 }
1414 #endif /* TARGET_ELF_ABI */
1415
1416 /* This function generates the assembly code for function exit.
1417 Args are as for output_function_prologue ().
1418
1419 The function epilogue should not depend on the current stack
1420 pointer! It should use the frame pointer only. This is mandatory
1421 because of alloca; we also take advantage of it to omit stack
1422 adjustments before returning. */
1423
1424 static void
1425 i370_output_function_epilogue (file, l)
1426 FILE *file;
1427 HOST_WIDE_INT l ATTRIBUTE_UNUSED;
1428 {
1429 int i;
1430
1431 check_label_emit ();
1432 mvs_check_page (file, 14, 0);
1433 fprintf (file, "* Function %s epilogue\n", mvs_function_name);
1434 mvs_page_num++;
1435
1436 #if MACROEPILOGUE == 1
1437 fprintf (file, "\tEDCEPIL\n");
1438 #else /* MACROEPILOGUE != 1 */
1439 fprintf (file, "\tL\t13,4(,13)\n");
1440 fprintf (file, "\tL\t14,12(,13)\n");
1441 fprintf (file, "\tLM\t2,12,28(13)\n");
1442 fprintf (file, "\tBALR\t1,14\n");
1443 fprintf (file, "\tDC\tA(");
1444 assemble_name (file, mvs_function_name);
1445 fprintf (file, ")\n" );
1446 #endif /* MACROEPILOGUE */
1447
1448 fprintf (file, "* Function %s literal pool\n", mvs_function_name);
1449 fprintf (file, "\tDS\t0F\n" );
1450 fprintf (file, "\tLTORG\n");
1451 fprintf (file, "* Function %s page table\n", mvs_function_name);
1452 fprintf (file, "\tDS\t0F\n");
1453 fprintf (file, "PGT%d\tEQU\t*\n", function_base_page);
1454
1455 mvs_free_label_list();
1456 for (i = function_base_page; i < mvs_page_num; i++)
1457 fprintf (file, "\tDC\tA(PG%d)\n", i);
1458 }
1459
1460 static void
1461 i370_file_start ()
1462 {
1463 fputs ("\tRMODE\tANY\n\tCSECT\n", asm_out_file);
1464 }
1465
1466 static void
1467 i370_file_end ()
1468 {
1469 fputs ("\tEND\n", asm_out_file);
1470 }
1471
1472 static void
1473 i370_internal_label (stream, prefix, labelno)
1474 FILE *stream;
1475 const char *prefix;
1476 unsigned long labelno;
1477 {
1478 if (!strcmp (prefix, "L"))
1479 mvs_add_label(labelno);
1480
1481 default_internal_label (stream, prefix, labelno);
1482 }
1483
1484 static bool
1485 i370_rtx_costs (x, code, outer_code, total)
1486 rtx x;
1487 int code;
1488 int outer_code ATTRIBUTE_UNUSED;
1489 int *total;
1490 {
1491 switch (code)
1492 {
1493 case CONST_INT:
1494 if ((unsigned HOST_WIDE_INT) INTVAL (x) < 0xfff)
1495 {
1496 *total = 1;
1497 return true;
1498 }
1499 /* FALLTHRU */
1500
1501 case CONST:
1502 case LABEL_REF:
1503 case SYMBOL_REF:
1504 *total = 2;
1505 return true;
1506
1507 case CONST_DOUBLE:
1508 *total = 4;
1509 return true;
1510
1511 default:
1512 return false;
1513 }
1514 }