1 /* Subroutines for insn-output.c for System/370.
2 Copyright (C) 1989, 93, 95, 97-99, 2000 Free Software Foundation, Inc.
3 Contributed by Jan Stein (jan@cd.chalmers.se).
4 Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
5 Hacked for Linux-ELF/390 by Linas Vepstas (linas@linas.org)
7 This file is part of GNU CC.
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
29 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
35 #include "insn-attr.h"
42 extern FILE *asm_out_file
;
44 /* Label node. This structure is used to keep track of labels
45 on the various pages in the current routine.
46 The label_id is the numeric ID of the label,
47 The label_page is the page on which it actually appears,
48 The first_ref_page is the page on which the true first ref appears.
49 The label_addr is an estimate of its location in the current routine,
50 The label_first & last_ref are estimates of where the earliest and
51 latest references to this label occur. */
53 typedef struct label_node
55 struct label_node
*label_next
;
66 /* Is 1 when a label has been generated and the base register must be reloaded. */
67 int mvs_need_base_reload
= 0;
69 /* Current function starting base page. */
70 int function_base_page
;
72 /* Length of the current page code. */
75 /* Length of the current page literals. */
78 /* Current function name. */
79 char *mvs_function_name
= 0;
81 /* Current function name length. */
82 int mvs_function_name_length
= 0;
84 /* Page number for multi-page functions. */
87 /* Label node list anchor. */
88 static label_node_t
*label_anchor
= 0;
90 /* Label node free list anchor. */
91 static label_node_t
*free_anchor
= 0;
93 /* Assembler source file descriptor. */
94 static FILE *assembler_source
= 0;
96 static label_node_t
* mvs_get_label
PARAMS ((int));
97 static void i370_label_scan
PARAMS ((void));
99 /* ===================================================== */
100 /* defines and functions specific to the HLASM assembler */
103 #ifndef MAX_MVS_LABEL_SIZE
104 #define MAX_MVS_LABEL_SIZE 8
107 #define MAX_LONG_LABEL_SIZE 255
109 /* Alias node, this structure is used to keep track of aliases to external
110 variables. The IBM assembler allows an alias to an external name
111 that is longer that 8 characters; but only once per assembly.
112 Also, this structure stores the #pragma map info. */
113 typedef struct alias_node
115 struct alias_node
*alias_next
;
117 char alias_name
[MAX_MVS_LABEL_SIZE
+ 1];
118 char real_name
[MAX_LONG_LABEL_SIZE
+ 1];
122 /* Alias node list anchor. */
123 static alias_node_t
*alias_anchor
= 0;
127 static int alias_number
= 0;
130 /* Define the length of the internal MVS function table. */
131 #define MVS_FUNCTION_TABLE_LENGTH 32
133 /* C/370 internal function table. These functions use non-standard linkage
134 and must handled in a special manner. */
135 static const char *const mvs_function_table
[MVS_FUNCTION_TABLE_LENGTH
] =
137 #if defined(HOST_EBCDIC) /* Changed for EBCDIC collating sequence */
138 "ceil", "edc_acos", "edc_asin", "edc_atan", "edc_ata2", "edc_cos",
139 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
140 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
141 "fabs", "floor", "fmod", "frexp", "hypot", "jn",
142 "j0", "j1", "ldexp", "modf", "pow", "yn",
145 "ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
146 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
147 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
148 "fabs", "floor", "fmod", "frexp", "hypot", "j0",
149 "j1", "jn", "ldexp", "modf", "pow", "y0",
154 #endif /* TARGET_HLASM */
155 /* ===================================================== */
157 /* ASCII to EBCDIC conversion table. */
158 static const unsigned char ascebc
[256] =
160 /*00 NL SH SX EX ET NQ AK BL */
161 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
162 /*08 BS HT LF VT FF CR SO SI */
163 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
164 /*10 DL D1 D2 D3 D4 NK SN EB */
165 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
166 /*18 CN EM SB EC FS GS RS US */
167 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
168 /*20 SP ! " # $ % & ' */
169 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
170 /*28 ( ) * + , - . / */
171 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
172 /*30 0 1 2 3 4 5 6 7 */
173 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
174 /*38 8 9 : ; < = > ? */
175 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
176 /*40 @ A B C D E F G */
177 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
178 /*48 H I J K L M N O */
179 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
180 /*50 P Q R S T U V W */
181 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
182 /*58 X Y Z [ \ ] ^ _ */
183 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
184 /*60 ` a b c d e f g */
185 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
186 /*68 h i j k l m n o */
187 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
188 /*70 p q r s t u v w */
189 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
190 /*78 x y z { | } ~ DL */
191 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
192 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
193 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
194 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
195 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
196 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
197 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
198 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
199 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
200 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
201 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
202 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
203 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
204 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
205 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
206 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
207 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
210 /* EBCDIC to ASCII conversion table. */
211 static const unsigned char ebcasc
[256] =
213 /*00 NU SH SX EX PF HT LC DL */
214 0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F,
215 /*08 SM VT FF CR SO SI */
216 0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
217 /*10 DE D1 D2 TM RS NL BS IL */
218 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x08, 0x00,
219 /*18 CN EM CC C1 FS GS RS US */
220 0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
221 /*20 DS SS FS BP LF EB EC */
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
223 /*28 SM C2 EQ AK BL */
224 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x00,
225 /*30 SY PN RS UC ET */
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
228 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
230 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
234 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
238 0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 /*78 ` : # @ ' = " */
244 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
245 /*80 a b c d e f g */
246 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
248 0x68, 0x69, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00,
249 /*90 j k l m n o p */
250 0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
252 0x71, 0x72, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,
253 /*A0 ~ s t u v w x */
254 0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
256 0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
261 /*C0 { A B C D E F G */
262 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
264 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 /*D0 } J K L M N O P */
266 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
268 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 /*E0 \ S T U V W X */
270 0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
272 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 /*F0 0 1 2 3 4 5 6 7 */
274 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
276 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
279 /* Map characters from one character set to another.
280 C is the character to be translated. */
286 #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
287 fprintf (stderr
, "mvs_map_char: TE & !HE: c = %02x\n", c
);
290 #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
291 fprintf (stderr
, "mvs_map_char: !TE & HE: c = %02x\n", c
);
294 fprintf (stderr
, "mvs_map_char: !TE & !HE: c = %02x\n", c
);
300 /* ===================================================== */
301 /* The following three routines are used to determine whther
302 forward branch is on this page, or is a far jump. We use
303 the "length" attr on an insn [(set_atter "length" "4")]
304 to store the largest possible code length that insn
305 could have. This gives us a hint of the address of a
306 branch destination, and from that, we can work out
307 the length of the jump, and whether its on page or not.
310 /* Return the destination address of a branch. */
313 i370_branch_dest (branch
)
316 rtx dest
= SET_SRC (PATTERN (branch
));
320 /* first, compute the estimated address of the branch target */
321 if (GET_CODE (dest
) == IF_THEN_ELSE
)
322 dest
= XEXP (dest
, 1);
323 dest
= XEXP (dest
, 0);
324 dest_uid
= INSN_UID (dest
);
325 dest_addr
= insn_addresses
[dest_uid
];
327 /* next, record the address of this insn as the true addr of first ref */
330 rtx label
= JUMP_LABEL (branch
);
331 int labelno
= CODE_LABEL_NUMBER (label
);
333 if (!label
|| CODE_LABEL
!= GET_CODE (label
)) abort ();
335 lp
= mvs_get_label (labelno
);
336 if (-1 == lp
-> first_ref_page
) lp
->first_ref_page
= mvs_page_num
;
342 i370_branch_length (insn
)
346 here
= insn_addresses
[INSN_UID (insn
)];
347 there
= i370_branch_dest (insn
);
348 return (there
- here
);
353 i370_short_branch (insn
)
358 base_offset
= i370_branch_length(insn
);
361 base_offset
+= mvs_page_code
;
365 /* avoid bumping into lit pool; use 2x to estimate max possible lits */
367 base_offset
+= mvs_page_code
+ mvs_page_lit
;
370 /* make a conservative estimate of room left on page */
371 if ((4060 >base_offset
) && ( 0 < base_offset
)) return 1;
375 /* The i370_label_scan() routine is supposed to loop over
376 all labels and label references in a compilation unit,
377 and determine whether all label refs appear on the same
378 code page as the label. If they do, then we can avoid
379 a reload of the base register for that label.
381 Note that the instruction addresses used here are only
382 approximate, and make the sizes of the jumps appear
383 farther apart then they will actually be. This makes
384 this code far more conservative than it needs to be.
387 #define I370_RECORD_LABEL_REF(label,addr) { \
389 int labelno = CODE_LABEL_NUMBER (label); \
390 lp = mvs_get_label (labelno); \
391 if (addr < lp -> label_first_ref) lp->label_first_ref = addr; \
392 if (addr > lp -> label_last_ref) lp->label_last_ref = addr; \
400 int tablejump_offset
= 0;
402 for (insn
= get_insns(); insn
; insn
= NEXT_INSN(insn
))
404 int here
= insn_addresses
[INSN_UID (insn
)];
405 enum rtx_code code
= GET_CODE(insn
);
407 /* ??? adjust for tables embedded in the .text section that
408 * the compiler didn't take into account */
409 here
+= tablejump_offset
;
410 insn_addresses
[INSN_UID (insn
)] = here
;
412 /* check to see if this insn is a label ... */
413 if (CODE_LABEL
== code
)
415 int labelno
= CODE_LABEL_NUMBER (insn
);
417 lp
= mvs_get_label (labelno
);
418 lp
-> label_addr
= here
;
420 /* Supposedly, labels are supposed to have circular
421 lists of label-refs that reference them,
422 setup in flow.c, but this does not appear to be the case. */
423 rtx labelref
= LABEL_REFS (insn
);
427 rtx linsn
= CONTAINING_INSN(ref
);
428 ref
= LABEL_NEXTREF(ref
);
429 } while (ref
&& (ref
!= labelref
));
433 if (JUMP_INSN
== code
)
435 rtx label
= JUMP_LABEL (insn
);
437 /* If there is no label for this jump, then this
438 had better be a ADDR_VEC or an ADDR_DIFF_VEC
439 and there had better be a vector of labels. */
443 rtx body
= PATTERN (insn
);
444 if (ADDR_VEC
== GET_CODE(body
))
446 for (j
=0; j
< XVECLEN (body
, 0); j
++)
448 rtx lref
= XVECEXP (body
, 0, j
);
449 if (LABEL_REF
!= GET_CODE (lref
)) abort ();
450 label
= XEXP (lref
,0);
451 if (CODE_LABEL
!= GET_CODE (label
)) abort ();
452 tablejump_offset
+= 4;
454 I370_RECORD_LABEL_REF(label
,here
);
456 /* finished with the vector go do next insn */
460 if (ADDR_DIFF_VEC
== GET_CODE(body
))
463 Right now, we leave this as a no-op, but strictly speaking,
464 this is incorrect. It is possible that a table-jump
465 driven off of a relative address could take us off-page,
466 to a place where we need to reload the base reg. So really,
467 we need to examing both labels, and compare thier values
468 to the current basereg value.
470 More generally, this brings up a troubling issue overall:
471 what happens if a tablejump is split across two pages? I do
472 not beleive that this case is handled correctly at all, and
473 can only lead to horrible results if this were to occur.
475 However, the current situation is not any worse than it was
476 last week, and so we punt for now. */
479 for (j
=0; j
< XVECLEN (body
, 0); j
++)
482 /* finished with the vector go do next insn */
488 Compiling the execption handling (L_eh) in libgcc2.a will trip
489 up right here, with something that looks like
490 (set (pc) (mem:SI (plus:SI (reg/v:SI 1 r1) (const_int 4))))
492 I'm not sure of what leads up to this, but it looks like
493 the makings of a long jump which will surely get us into trouble
494 because the base & page registers don't get reloaded. For now
495 I'm not sure of what to do ... again we punt ... we are not worse
496 off than yesterday. */
498 /* print_rtl_single (stdout, insn); */
506 /* At this point, this jump_insn had better be a plain-old
507 ordinary one, grap the label id and go */
508 if (CODE_LABEL
!= GET_CODE (label
)) abort ();
509 I370_RECORD_LABEL_REF(label
,here
);
513 /* Sometimes, we take addresses of labels and use them
514 as instruction operands ... these show up as REG_NOTES */
518 if ('i' == GET_RTX_CLASS (code
))
521 for (note
= REG_NOTES (insn
); note
; note
= XEXP(note
,1))
523 if (REG_LABEL
== REG_NOTE_KIND(note
))
525 rtx label
= XEXP (note
,0);
526 if (!label
|| CODE_LABEL
!= GET_CODE (label
)) abort ();
528 I370_RECORD_LABEL_REF(label
,here
);
536 /* ===================================================== */
538 /* Emit reload of base register if indicated. This is to eliminate multiple
539 reloads when several labels are generated pointing to the same place
542 The page table is written at the end of the function.
543 The entries in the page table look like
544 .LPGT0: // PGT0 EQU *
545 .long .LPG0 // DC A(PG0)
546 .long .LPG1 // DC A(PG1)
547 while the prologue generates
550 Note that this paging scheme breaks down if a single subroutine
551 has more than about 10MB of code in it ... as long as humans write
552 code, this shouldn't be a problem ...
558 if (mvs_need_base_reload
)
560 mvs_need_base_reload
= 0;
563 fprintf (assembler_source
, "\tL\t%d,%d(,%d)\n",
564 BASE_REGISTER
, (mvs_page_num
- function_base_page
) * 4,
569 /* Add the label to the current page label list. If a free element is available
570 it will be used for the new label. Otherwise, a label element will be
571 allocated from memory.
572 ID is the label number of the label being added to the list. */
580 /* first, lets see if we already go one, if so, use that. */
581 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
583 if (lp
->label_id
== id
) return lp
;
586 /* not found, get a new one */
590 free_anchor
= lp
->label_next
;
594 lp
= (label_node_t
*) xmalloc (sizeof (label_node_t
));
597 /* initialize for new label */
600 lp
->label_next
= label_anchor
;
601 lp
->label_first_ref
= 2000123123;
602 lp
->label_last_ref
= -1;
604 lp
->first_ref_page
= -1;
617 lp
= mvs_get_label (id
);
618 lp
->label_page
= mvs_page_num
;
620 /* OK, we just saw the label. Determine if this label
621 * needs a reload of the base register */
622 if ((-1 != lp
->first_ref_page
) &&
623 (lp
->first_ref_page
!= mvs_page_num
))
625 /* Yep; the first label_ref was on a different page. */
626 mvs_need_base_reload
++;
630 /* Hmm. Try to see if the estimated address of the last
631 label_ref is on the current page. If it is, then we
632 don't need a base reg reload. Note that this estimate
633 is very conservatively handled; we'll tend to have
634 a good bit more reloads than actually needed. Someday,
635 we should tighten the estimates (which are driven by
636 the (set_att "length") insn attibute.
638 Currently, we estimate that number of page literals
639 same as number of insns, which is a vast overestimate,
640 esp that the estimate of each insn size is its max size. */
642 /* if latest ref comes before label, we are clear */
643 if (lp
->label_last_ref
< lp
->label_addr
) return;
645 fwd_distance
= lp
->label_last_ref
- lp
->label_addr
;
647 if (mvs_page_code
+ 2*fwd_distance
+ mvs_page_lit
< 4060) return;
649 mvs_need_base_reload
++;
652 /* Check to see if the label is in the list and in the current
653 page. If not found, we have to make worst case assumption
654 that label will be on a different page, and thus will have to
655 generate a load and branch on register. This is rather
656 ugly for forward-jumps, but what can we do? For backward
657 jumps on the same page we can branch directly to address.
658 ID is the label number of the label being checked. */
666 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
668 if (lp
->label_id
== id
)
670 if (lp
->label_page
== mvs_page_num
)
683 /* Get the page on which the label sits. This will be used to
684 determine is a register reload is really needed. */
687 mvs_get_label_page(int id
)
691 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
693 if (lp
->label_id
== id
)
694 return lp
->label_page
;
699 /* The label list for the current page freed by linking the list onto the free
700 label element chain. */
703 mvs_free_label_list ()
708 label_node_t
*last_lp
= label_anchor
;
709 while (last_lp
->label_next
) last_lp
= last_lp
->label_next
;
710 last_lp
->label_next
= free_anchor
;
711 free_anchor
= label_anchor
;
716 /* ====================================================================== */
717 /* If the page size limit is reached a new code page is started, and the base
718 register is set to it. This page break point is counted conservatively,
719 most literals that have the same value are collapsed by the assembler.
720 True is returned when a new page is started.
721 FILE is the assembler output file descriptor.
722 CODE is the length, in bytes, of the instruction to be emitted.
723 LIT is the length of the literal to be emitted. */
727 mvs_check_page (file
, code
, lit
)
732 assembler_source
= file
;
734 if (mvs_page_code
+ code
+ mvs_page_lit
+ lit
> MAX_MVS_PAGE_LENGTH
)
736 fprintf (assembler_source
, "\tB\tPGE%d\n", mvs_page_num
);
737 fprintf (assembler_source
, "\tDS\t0F\n");
738 fprintf (assembler_source
, "\tLTORG\n");
739 fprintf (assembler_source
, "\tDS\t0F\n");
740 fprintf (assembler_source
, "PGE%d\tEQU\t*\n", mvs_page_num
);
741 fprintf (assembler_source
, "\tDROP\t%d\n", BASE_REGISTER
);
743 /* Safe to use BASR not BALR, since we are
744 * not switching addressing mode here ... */
745 fprintf (assembler_source
, "\tBASR\t%d,0\n", BASE_REGISTER
);
746 fprintf (assembler_source
, "PG%d\tEQU\t*\n", mvs_page_num
);
747 fprintf (assembler_source
, "\tUSING\t*,%d\n", BASE_REGISTER
);
748 mvs_page_code
= code
;
752 mvs_page_code
+= code
;
756 #endif /* TARGET_HLASM */
759 #ifdef TARGET_ELF_ABI
761 mvs_check_page (file
, code
, lit
)
766 assembler_source
= file
;
768 if (mvs_page_code
+ code
+ mvs_page_lit
+ lit
> MAX_MVS_PAGE_LENGTH
)
770 /* hop past the literal pool */
771 fprintf (assembler_source
, "\tB\t.LPGE%d\n", mvs_page_num
);
773 /* dump the literal pool. The .baligns are optional, since
774 * ltorg will align to the size of the largest literal
775 * (which is possibly 8 bytes) */
776 fprintf (assembler_source
, "\t.balign\t4\n");
777 fprintf (assembler_source
, "\t.LTORG\n");
778 fprintf (assembler_source
, "\t.balign\t4\n");
780 /* we continue execution here ... */
781 fprintf (assembler_source
, ".LPGE%d:\n", mvs_page_num
);
782 fprintf (assembler_source
, "\t.DROP\t%d\n", BASE_REGISTER
);
785 /* BASR puts the contents of the PSW into r3
786 * that is, r3 will be loaded with the address of "." */
787 fprintf (assembler_source
, "\tBASR\tr%d,0\n", BASE_REGISTER
);
788 fprintf (assembler_source
, ".LPG%d:\n", mvs_page_num
);
789 fprintf (assembler_source
, "\t.USING\t.,r%d\n", BASE_REGISTER
);
790 mvs_page_code
= code
;
794 mvs_page_code
+= code
;
798 #endif /* TARGET_ELF_ABI */
800 /* ===================================================== */
801 /* defines and functions specific to the HLASM assembler */
804 /* Check for C/370 runtime function, they don't use standard calling
805 conventions. True is returned if the function is in the table.
806 NAME is the name of the current function. */
809 mvs_function_check (name
)
812 int lower
, middle
, upper
;
816 upper
= MVS_FUNCTION_TABLE_LENGTH
- 1;
817 while (lower
<= upper
)
819 middle
= (lower
+ upper
) / 2;
820 i
= strcmp (name
, mvs_function_table
[middle
]);
832 /* Add the alias to the current alias list. */
835 mvs_add_alias (realname
, aliasname
, emitted
)
836 const char *realname
;
837 const char *aliasname
;
842 ap
= (alias_node_t
*) xmalloc (sizeof (alias_node_t
));
843 strcpy (ap
->real_name
, realname
);
844 strcpy (ap
->alias_name
, aliasname
);
845 ap
->alias_emitted
= emitted
;
846 ap
->alias_next
= alias_anchor
;
850 /* Check to see if the name needs aliasing */
853 mvs_need_alias (realname
)
854 const char *realname
;
856 if (mvs_function_check (realname
))
858 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
860 if (strchr (realname
, '_') != 0)
865 /* Get the alias from the list.
866 If 1 is returned then it's in the alias list, 0 if it was not */
869 mvs_get_alias (realname
, aliasname
)
870 const char *realname
;
876 for (ap
= alias_anchor
; ap
; ap
= ap
->alias_next
)
878 if (!strcmp (ap
->real_name
, realname
))
880 strcpy (aliasname
, ap
->alias_name
);
884 if (mvs_need_alias (realname
))
886 sprintf (aliasname
, "ALS%05d", alias_number
++);
887 mvs_add_alias (realname
, aliasname
, 0);
891 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
893 strncpy (aliasname
, realname
, MAX_MVS_LABEL_SIZE
);
894 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
901 /* Check to see if the alias is in the list.
902 If 1 is returned then it's in the alias list, 2 it was emitted */
905 mvs_check_alias (realname
, aliasname
)
906 const char *realname
;
912 for (ap
= alias_anchor
; ap
; ap
= ap
->alias_next
)
914 if (!strcmp (ap
->real_name
, realname
))
916 int rc
= (ap
->alias_emitted
== 1) ? 1 : 2;
917 strcpy (aliasname
, ap
->alias_name
);
918 ap
->alias_emitted
= 1;
922 if (mvs_need_alias (realname
))
924 sprintf (aliasname
, "ALS%05d", alias_number
++);
925 mvs_add_alias (realname
, aliasname
, 0);
926 alias_anchor
->alias_emitted
= 1;
930 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
932 strncpy (aliasname
, realname
, MAX_MVS_LABEL_SIZE
);
933 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
940 /* Called from check_newline via the macro HANDLE_PRAGMA.
941 FINPUT is the source file input stream.
942 NODE is the tree node for the token after the "pragma".
943 The result is 1 if the pragma was handled. */
946 handle_pragma (p_getc
, p_ungetc
, pname
)
947 int (* p_getc
) PARAMS ((void));
948 void (* p_ungetc
) PARAMS ((int));
954 if (strcmp (pname
, "map") == 0)
956 char realname
[MAX_LONG_LABEL_SIZE
+ 1];
957 char aliasname
[MAX_MVS_LABEL_SIZE
+ 1];
962 } while (c
== ' ' || c
== '\t');
969 } while (c
== ' ' || c
== '\t');
975 } while (ISALNUM(c
) || c
== '_');
980 if (c
== ' ' || c
== '\t')
983 } while (c
== ' ' || c
== '\t');
989 } while (c
== ' ' || c
== '\t');
1000 if (c
>= '0' && c
<= '7')
1001 d
= (d
<< 3) | (c
- '0');
1002 } while (c
>= '0' && c
<= '7');
1005 if (d
< 1 || d
> 255)
1006 warning ("Escape value out of range");
1013 if (ISSPACE(c
) || c
== ')')
1014 goto PRAGMA_WARNING
;
1017 if (strlen (aliasname
) > MAX_MVS_LABEL_SIZE
)
1019 warning ("#pragma map alias is too long, truncated");
1020 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
1024 } while (c
== ' ' || c
== '\t');
1027 mvs_add_alias (realname
, aliasname
, 1);
1031 goto PRAGMA_WARNING
;
1034 goto PRAGMA_WARNING
;
1037 goto PRAGMA_WARNING
;
1043 warning ("#pragma map options are missing or incorrect");
1051 /* defines and functions specific to the HLASM assembler */
1052 #endif /* TARGET_HLASM */
1053 /* ===================================================== */
1054 /* ===================================================== */
1055 /* defines and functions specific to the gas assembler */
1056 #ifdef TARGET_ELF_ABI
1058 /* Check for C/370 runtime function, they don't use standard calling
1059 conventions. True is returned if the function is in the table.
1060 NAME is the name of the current function. */
1061 /* no special calling conventions (yet ??) */
1064 mvs_function_check (name
)
1065 const char *name ATTRIBUTE_UNUSED
;
1070 #endif /* TARGET_ELF_ABI */
1071 /* ===================================================== */
1074 /* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
1075 OP is the current operation.
1076 MODE is the current operation mode. */
1079 s_operand (op
, mode
)
1081 enum machine_mode mode
;
1083 extern int volatile_ok
;
1084 register enum rtx_code code
= GET_CODE (op
);
1086 if (CONSTANT_ADDRESS_P (op
))
1088 if (mode
== VOIDmode
|| GET_MODE (op
) != mode
)
1092 register rtx x
= XEXP (op
, 0);
1094 if (!volatile_ok
&& op
->volatil
)
1096 if (REG_P (x
) && REG_OK_FOR_BASE_P (x
))
1098 if (GET_CODE (x
) == PLUS
1099 && REG_P (XEXP (x
, 0)) && REG_OK_FOR_BASE_P (XEXP (x
, 0))
1100 && GET_CODE (XEXP (x
, 1)) == CONST_INT
1101 && (unsigned) INTVAL (XEXP (x
, 1)) < 4096)
1108 /* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
1110 OP is the current operation.
1111 MODE is the current operation mode. */
1114 r_or_s_operand (op
, mode
)
1116 enum machine_mode mode
;
1118 extern int volatile_ok
;
1119 register enum rtx_code code
= GET_CODE (op
);
1121 if (CONSTANT_ADDRESS_P (op
))
1123 if (mode
== VOIDmode
|| GET_MODE (op
) != mode
)
1127 else if (code
== MEM
)
1129 register rtx x
= XEXP (op
, 0);
1131 if (!volatile_ok
&& op
->volatil
)
1133 if (REG_P (x
) && REG_OK_FOR_BASE_P (x
))
1135 if (GET_CODE (x
) == PLUS
1136 && REG_P (XEXP (x
, 0)) && REG_OK_FOR_BASE_P (XEXP (x
, 0))
1137 && GET_CODE (XEXP (x
, 1)) == CONST_INT
1138 && (unsigned) INTVAL (XEXP (x
, 1)) < 4096)
1145 /* Some remarks about unsigned_jump_follows_p():
1146 gcc is built around the assumption that branches are signed
1147 or unsigned, whereas the 370 doesn't care; its the compares that
1148 are signed or unsigned. Thus, we need to somehow know if we
1149 need to do a signed or an unsigned compare, and we do this by
1150 looking ahead in the instruction sequence until we find a jump.
1151 We then note whether this jump is signed or unsigned, and do the
1152 compare appropriately. Note that we have to scan ahead indefinitley,
1153 as the gcc optimizer may insert any number of instructions between
1154 the compare and the jump.
1156 Note that using conditional branch expanders seems to be be a more
1157 elegant/correct way of doing this. See, for instance, the Alpha
1158 cmpdi and bgt patterns. Note also that for the i370, various
1159 arithmetic insn's set the condition code as well.
1161 The unsigned_jump_follows_p() routine returns a 1 if the next jump
1162 is unsigned. INSN is the current instruction. */
1165 unsigned_jump_follows_p (insn
)
1168 rtx orig_insn
= insn
;
1171 register rtx tmp_insn
;
1174 insn
= NEXT_INSN (insn
);
1175 if (!insn
) fatal_insn ("internal error--no jump follows compare:", orig_insn
);
1177 if (GET_CODE (insn
) != JUMP_INSN
) continue;
1179 tmp_insn
= XEXP (insn
, 3);
1180 if (GET_CODE (tmp_insn
) != SET
) continue;
1182 if (GET_CODE (XEXP (tmp_insn
, 0)) != PC
) continue;
1184 tmp_insn
= XEXP (tmp_insn
, 1);
1185 if (GET_CODE (tmp_insn
) != IF_THEN_ELSE
) continue;
1187 /* if we got to here, this instruction is a jump. Is it signed? */
1188 tmp_insn
= XEXP (tmp_insn
, 0);
1189 coda
= GET_CODE (tmp_insn
);
1191 return coda
!= GE
&& coda
!= GT
&& coda
!= LE
&& coda
!= LT
;
1199 i370_function_prolog (f
, l
)
1203 #if MACROPROLOGUE == 1
1204 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1205 fprintf (f
, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
1206 STACK_POINTER_OFFSET
+ l
- 120 +
1207 current_function_outgoing_args_size
, BASE_REGISTER
);
1208 #else /* MACROPROLOGUE != 1 */
1209 static int function_label_index
= 1;
1210 static int function_first
= 0;
1211 static int function_year
, function_month
, function_day
;
1212 static int function_hour
, function_minute
, function_second
;
1214 if (!function_first
)
1216 struct tm
*function_time
;
1219 function_time
= localtime (&lcltime
);
1220 function_year
= function_time
->tm_year
+ 1900;
1221 function_month
= function_time
->tm_mon
+ 1;
1222 function_day
= function_time
->tm_mday
;
1223 function_hour
= function_time
->tm_hour
;
1224 function_minute
= function_time
->tm_min
;
1225 function_second
= function_time
->tm_sec
;
1227 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1228 fprintf (f
, "FDSE%03d\tDSECT\n", function_label_index
);
1229 fprintf (f
, "\tDS\tD\n");
1230 fprintf (f
, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET
+ l
1231 + current_function_outgoing_args_size
);
1232 fprintf (f
, "\tORG\tFDSE%03d\n", function_label_index
);
1233 fprintf (f
, "\tDS\tCL(120+8)\n");
1234 fprintf (f
, "\tORG\n");
1235 fprintf (f
, "\tDS\t0D\n");
1236 fprintf (f
, "FDSL%03d\tEQU\t*-FDSE%03d-8\n", function_label_index
,
1237 function_label_index
);
1238 fprintf (f
, "\tDS\t0H\n");
1239 assemble_name (f
, mvs_function_name
);
1240 fprintf (f
, "\tCSECT\n");
1241 fprintf (f
, "\tUSING\t*,15\n");
1242 fprintf (f
, "\tB\tFENT%03d\n", function_label_index
);
1243 fprintf (f
, "\tDC\tAL1(FNAM%03d+4-*)\n", function_label_index
);
1244 fprintf (f
, "\tDC\tX'CE',X'A0',AL1(16)\n");
1245 fprintf (f
, "\tDC\tAL4(FPPA%03d)\n", function_label_index
);
1246 fprintf (f
, "\tDC\tAL4(0)\n");
1247 fprintf (f
, "\tDC\tAL4(FDSL%03d)\n", function_label_index
);
1248 fprintf (f
, "FNAM%03d\tEQU\t*\n", function_label_index
);
1249 fprintf (f
, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name
),
1251 fprintf (f
, "FPPA%03d\tDS\t0F\n", function_label_index
);
1252 fprintf (f
, "\tDC\tX'03',X'00',X'33',X'00'\n");
1253 fprintf (f
, "\tDC\tV(CEESTART)\n");
1254 fprintf (f
, "\tDC\tAL4(0)\n");
1255 fprintf (f
, "\tDC\tAL4(FTIM%03d)\n", function_label_index
);
1256 fprintf (f
, "FTIM%03d\tDS\t0F\n", function_label_index
);
1257 fprintf (f
, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1258 function_year
, function_month
, function_day
,
1259 function_hour
, function_minute
);
1260 fprintf (f
, "\tDC\tCL2'01',CL4'0100'\n");
1261 fprintf (f
, "FENT%03d\tDS\t0H\n", function_label_index
);
1262 fprintf (f
, "\tSTM\t14,12,12(13)\n");
1263 fprintf (f
, "\tL\t2,76(,13)\n");
1264 fprintf (f
, "\tL\t0,16(,15)\n");
1265 fprintf (f
, "\tALR\t0,2\n");
1266 fprintf (f
, "\tCL\t0,12(,12)\n");
1267 fprintf (f
, "\tBNH\t*+10\n");
1268 fprintf (f
, "\tL\t15,116(,12)\n");
1269 fprintf (f
, "\tBALR\t14,15\n");
1270 fprintf (f
, "\tL\t15,72(,13)\n");
1271 fprintf (f
, "\tSTM\t15,0,72(2)\n");
1272 fprintf (f
, "\tMVI\t0(2),X'10'\n");
1273 fprintf (f
, "\tST\t2,8(,13)\n ");
1274 fprintf (f
, "\tST\t13,4(,2)\n ");
1275 fprintf (f
, "\tLR\t13,2\n");
1276 fprintf (f
, "\tDROP\t15\n");
1277 fprintf (f
, "\tBALR\t%d,0\n", BASE_REGISTER
);
1278 fprintf (f
, "\tUSING\t*,%d\n", BASE_REGISTER
);
1280 function_label_index
++;
1282 if (!function_first
)
1284 struct tm
*function_time
;
1287 function_time
= localtime (&lcltime
);
1288 function_year
= function_time
->tm_year
+ 1900;
1289 function_month
= function_time
->tm_mon
+ 1;
1290 function_day
= function_time
->tm_mday
;
1291 function_hour
= function_time
->tm_hour
;
1292 function_minute
= function_time
->tm_min
;
1293 function_second
= function_time
->tm_sec
;
1294 fprintf (f
, "PPA2\tDS\t0F\n");
1295 fprintf (f
, "\tDC\tX'03',X'00',X'33',X'00'\n");
1296 fprintf (f
, "\tDC\tV(CEESTART),A(0)\n");
1297 fprintf (f
, "\tDC\tA(CEETIMES)\n");
1298 fprintf (f
, "CEETIMES\tDS\t0F\n");
1299 fprintf (f
, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1300 function_year
, function_month
, function_day
,
1301 function_hour
, function_minute
, function_second
);
1302 fprintf (f
, "\tDC\tCL2'01',CL4'0100'\n");
1304 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1305 fprintf (f
, "FDSD%03d\tDSECT\n", function_label_index
);
1306 fprintf (f
, "\tDS\tD\n");
1307 fprintf (f
, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET
+ l
1308 + current_function_outgoing_args_size
);
1309 fprintf (f
, "\tORG\tFDSD%03d\n", function_label_index
);
1310 fprintf (f
, "\tDS\tCL(120+8)\n");
1311 fprintf (f
, "\tORG\n");
1312 fprintf (f
, "\tDS\t0D\n");
1313 fprintf (f
, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index
,
1314 function_label_index
);
1315 fprintf (f
, "\tDS\t0H\n");
1316 assemble_name (f
, mvs_function_name
);
1317 fprintf (f
, "\tCSECT\n");
1318 fprintf (f
, "\tUSING\t*,15\n");
1319 fprintf (f
, "\tB\tFPL%03d\n", function_label_index
);
1320 fprintf (f
, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index
+ 1);
1321 fprintf (f
, "\tDC\tX'CE',X'A0',AL1(16)\n");
1322 fprintf (f
, "\tDC\tAL4(PPA2)\n");
1323 fprintf (f
, "\tDC\tAL4(0)\n");
1324 fprintf (f
, "\tDC\tAL4(FDSL%03d)\n", function_label_index
);
1325 fprintf (f
, "FPL%03d\tEQU\t*\n", function_label_index
+ 1);
1326 fprintf (f
, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name
),
1328 fprintf (f
, "FPL%03d\tDS\t0H\n", function_label_index
);
1329 fprintf (f
, "\tSTM\t14,12,12(13)\n");
1330 fprintf (f
, "\tL\t2,76(,13)\n");
1331 fprintf (f
, "\tL\t0,16(,15)\n");
1332 fprintf (f
, "\tALR\t0,2\n");
1333 fprintf (f
, "\tCL\t0,12(,12)\n");
1334 fprintf (f
, "\tBNH\t*+10\n");
1335 fprintf (f
, "\tL\t15,116(,12)\n");
1336 fprintf (f
, "\tBALR\t14,15\n");
1337 fprintf (f
, "\tL\t15,72(,13)\n");
1338 fprintf (f
, "\tSTM\t15,0,72(2)\n");
1339 fprintf (f
, "\tMVI\t0(2),X'10'\n");
1340 fprintf (f
, "\tST\t2,8(,13)\n ");
1341 fprintf (f
, "\tST\t13,4(,2)\n ");
1342 fprintf (f
, "\tLR\t13,2\n");
1343 fprintf (f
, "\tDROP\t15\n");
1344 fprintf (f
, "\tBALR\t%d,0\n", BASE_REGISTER
);
1345 fprintf (f
, "\tUSING\t*,%d\n", BASE_REGISTER
);
1347 function_label_index
+= 2;
1349 #endif /* MACROPROLOGUE */
1350 fprintf (f
, "PG%d\tEQU\t*\n", mvs_page_num
);
1351 fprintf (f
, "\tLR\t11,1\n");
1352 fprintf (f
, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER
, mvs_page_num
);
1353 fprintf (f
, "* Function %s code\n", mvs_function_name
);
1355 mvs_free_label_list ();
1358 mvs_check_page (f
, 0, 0);
1359 function_base_page
= mvs_page_num
;
1361 /* find all labels in this routine */
1364 #endif /* TARGET_HLASM */
1367 #ifdef TARGET_ELF_ABI
1369 The 370_function_prolog() routine generates the current ELF ABI ES/390 prolog.
1370 It implements a stack that grows downward.
1371 It performs the following steps:
1372 -- saves the callers non-volatile registers on the callers stack.
1373 -- subtracts stackframe size from the stack pointer.
1374 -- stores backpointer to old caller stack.
1376 XXX hack alert -- if the global var int leaf_function is non-zero,
1377 then this is a leaf, and it might be possible to optimize the prologue
1378 into doing even less, e.g. not grabbing a new stackframe or maybe just a
1379 partial stack frame.
1381 XXX hack alert -- the current stack frame is bloated into twice the
1382 needed size by unused entries. These entries make it marginally
1383 compatible with MVS/OE/USS C environment, but really they're not used
1384 and could probably chopped out. Modifications to i370.md would be needed
1385 also, to quite using addresses 136, 140, etc.
1389 i370_function_prolog (f
, frame_size
)
1393 static int function_label_index
= 1;
1394 static int function_first
= 0;
1395 int stackframe_size
, aligned_size
;
1397 fprintf (f
, "# Function prologue\n");
1398 /* define the stack, put it into its own data segment
1399 FDSE == Function Stack Entry
1400 FDSL == Function Stack Length */
1402 STACK_POINTER_OFFSET
+ current_function_outgoing_args_size
+ frame_size
;
1403 aligned_size
= (stackframe_size
+ 7) >> 3;
1406 fprintf (f
, "# arg_size=0x%x frame_size=0x%x aligned size=0x%x\n",
1407 current_function_outgoing_args_size
, frame_size
, aligned_size
);
1409 fprintf (f
, "\t.using\t.,r15\n");
1411 /* Branch to exectuable part of prologue. */
1412 fprintf (f
, "\tB\t.LFENT%03d\n", function_label_index
);
1414 /* write the length of the stackframe */
1415 fprintf (f
, "\t.long\t%d\n", aligned_size
);
1417 /* FENT == function prologue entry */
1418 fprintf (f
, "\t.balign 2\n.LFENT%03d:\n",
1419 function_label_index
);
1421 /* store multiple registers 14,15,0,...12 at 12 bytes from sp */
1422 fprintf (f
, "\tSTM\tr14,r12,12(sp)\n");
1424 /* r3 == saved callee stack pointer */
1425 fprintf (f
, "\tLR\tr3,sp\n");
1427 /* 4(r15) == stackframe size */
1428 fprintf (f
, "\tSL\tsp,4(,r15)\n");
1430 /* r11 points to arg list in callers stackframe; was passed in r2 */
1431 fprintf (f
, "\tLR\tr11,r2\n");
1433 /* store callee stack pointer at 8(sp) */
1434 /* fprintf (f, "\tST\tsp,8(,r3)\n "); wasted cycles, no one uses this ... */
1436 /* backchain -- store caller sp at 4(callee_sp) */
1437 fprintf (f
, "\tST\tr3,4(,sp)\n ");
1439 fprintf (f
, "\t.drop\tr15\n");
1440 /* Place contents of the PSW into r3
1441 that is, place the address of "." into r3 */
1442 fprintf (f
, "\tBASR\tr%d,0\n", BASE_REGISTER
);
1443 fprintf (f
, "\t.using\t.,r%d\n", BASE_REGISTER
);
1445 function_label_index
++;
1447 fprintf (f
, ".LPG%d:\n", mvs_page_num
);
1448 fprintf (f
, "\tL\tr%d,=A(.LPGT%d)\n", PAGE_REGISTER
, mvs_page_num
);
1449 fprintf (f
, "# Function code\n");
1451 mvs_free_label_list ();
1454 mvs_check_page (f
, 0, 0);
1455 function_base_page
= mvs_page_num
;
1457 /* find all labels in this routine */
1460 #endif /* TARGET_ELF_ABI */