1 /* Subroutines for insn-output.c for System/370.
2 Copyright (C) 1989, 93, 95, 97, 98, 1999 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"
36 /* #include "function.h" */
40 extern FILE *asm_out_file
;
42 /* Label node. This structure is used to keep track of labels
43 on the various pages in the current routine.
44 The label_id is the numeric ID of the label,
45 The label_page is the page on which it actually appears,
46 The first_ref_page is the page on which the true first ref appears.
47 The label_addr is an estimate of its location in the current routine,
48 The label_first & last_ref are estimates of where the earliest and
49 latest references to this label occur. */
51 typedef struct label_node
53 struct label_node
*label_next
;
64 /* Is 1 when a label has been generated and the base register must be reloaded. */
65 int mvs_need_base_reload
= 0;
67 /* Current function starting base page. */
68 int function_base_page
;
70 /* Length of the current page code. */
73 /* Length of the current page literals. */
76 /* Current function name. */
77 char *mvs_function_name
= 0;
79 /* Current function name length. */
80 int mvs_function_name_length
= 0;
82 /* Page number for multi-page functions. */
85 /* Label node list anchor. */
86 static label_node_t
*label_anchor
= 0;
88 /* Label node free list anchor. */
89 static label_node_t
*free_anchor
= 0;
91 /* Assembler source file descriptor. */
92 static FILE *assembler_source
= 0;
94 label_node_t
* mvs_get_label ();
96 /* ===================================================== */
97 /* defines and functions specific to the HLASM assembler */
100 #ifndef MAX_MVS_LABEL_SIZE
101 #define MAX_MVS_LABEL_SIZE 8
104 #define MAX_LONG_LABEL_SIZE 255
106 /* Alias node, this structure is used to keep track of aliases to external
107 variables. The IBM assembler allows an alias to an external name
108 that is longer that 8 characters; but only once per assembly.
109 Also, this structure stores the #pragma map info. */
110 typedef struct alias_node
112 struct alias_node
*alias_next
;
114 char alias_name
[MAX_MVS_LABEL_SIZE
+ 1];
115 char real_name
[MAX_LONG_LABEL_SIZE
+ 1];
119 /* Alias node list anchor. */
120 static alias_node_t
*alias_anchor
= 0;
123 static alias_number
= 0;
125 /* Define the length of the internal MVS function table. */
126 #define MVS_FUNCTION_TABLE_LENGTH 32
128 /* C/370 internal function table. These functions use non-standard linkage
129 and must handled in a special manner. */
130 static char *mvs_function_table
[MVS_FUNCTION_TABLE_LENGTH
] =
132 #if defined(HOST_EBCDIC) /* Changed for EBCDIC collating sequence */
133 "ceil", "edc_acos", "edc_asin", "edc_atan", "edc_ata2", "edc_cos",
134 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
135 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
136 "fabs", "floor", "fmod", "frexp", "hypot", "jn",
137 "j0", "j1", "ldexp", "modf", "pow", "yn",
140 "ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
141 "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
142 "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
143 "fabs", "floor", "fmod", "frexp", "hypot", "j0",
144 "j1", "jn", "ldexp", "modf", "pow", "y0",
149 #endif /* TARGET_HLASM */
150 /* ===================================================== */
152 /* ASCII to EBCDIC conversion table. */
153 static unsigned char ascebc
[256] =
155 /*00 NL SH SX EX ET NQ AK BL */
156 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
157 /*08 BS HT LF VT FF CR SO SI */
158 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
159 /*10 DL D1 D2 D3 D4 NK SN EB */
160 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
161 /*18 CN EM SB EC FS GS RS US */
162 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
163 /*20 SP ! " # $ % & ' */
164 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
165 /*28 ( ) * + , - . / */
166 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
167 /*30 0 1 2 3 4 5 6 7 */
168 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
169 /*38 8 9 : ; < = > ? */
170 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
171 /*40 @ A B C D E F G */
172 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
173 /*48 H I J K L M N O */
174 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
175 /*50 P Q R S T U V W */
176 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
177 /*58 X Y Z [ \ ] ^ _ */
178 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
179 /*60 ` a b c d e f g */
180 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
181 /*68 h i j k l m n o */
182 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
183 /*70 p q r s t u v w */
184 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
185 /*78 x y z { | } ~ DL */
186 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
187 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
188 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
189 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
190 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
191 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
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, 0xFF
205 /* EBCDIC to ASCII conversion table. */
206 unsigned char ebcasc
[256] =
208 /*00 NU SH SX EX PF HT LC DL */
209 0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F,
210 /*08 SM VT FF CR SO SI */
211 0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
212 /*10 DE D1 D2 TM RS NL BS IL */
213 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x08, 0x00,
214 /*18 CN EM CC C1 FS GS RS US */
215 0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
216 /*20 DS SS FS BP LF EB EC */
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
218 /*28 SM C2 EQ AK BL */
219 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x00,
220 /*30 SY PN RS UC ET */
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
223 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
225 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
229 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
233 0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 /*78 ` : # @ ' = " */
239 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
240 /*80 a b c d e f g */
241 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
243 0x68, 0x69, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00,
244 /*90 j k l m n o p */
245 0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
247 0x71, 0x72, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,
248 /*A0 ~ s t u v w x */
249 0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
251 0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
256 /*C0 { A B C D E F G */
257 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
259 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 /*D0 } J K L M N O P */
261 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
263 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 /*E0 \ S T U V W X */
265 0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
267 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 /*F0 0 1 2 3 4 5 6 7 */
269 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
271 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
274 /* Map characters from one character set to another.
275 C is the character to be translated. */
281 #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
282 fprintf (stderr
, "mvs_map_char: TE & !HE: c = %02x\n", c
);
285 #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
286 fprintf (stderr
, "mvs_map_char: !TE & HE: c = %02x\n", c
);
289 fprintf (stderr
, "mvs_map_char: !TE & !HE: c = %02x\n", c
);
295 /* ===================================================== */
296 /* The following three routines are used to determine whther
297 forward branch is on this page, or is a far jump. We use
298 the "length" attr on an insn [(set_atter "length" "4")]
299 to store the largest possible code length that insn
300 could have. This gives us a hint of the address of a
301 branch destination, and from that, we can work out
302 the length of the jump, and whether its on page or not.
305 /* Return the destination address of a branch. */
308 i370_branch_dest (branch
)
311 rtx dest
= SET_SRC (PATTERN (branch
));
315 /* first, compute the estimated address of the branch target */
316 if (GET_CODE (dest
) == IF_THEN_ELSE
)
317 dest
= XEXP (dest
, 1);
318 dest
= XEXP (dest
, 0);
319 dest_uid
= INSN_UID (dest
);
320 dest_addr
= insn_addresses
[dest_uid
];
322 /* next, record the address of this insn as the true addr of first ref */
325 rtx label
= JUMP_LABEL (branch
);
326 int labelno
= CODE_LABEL_NUMBER (label
);
328 if (!label
|| CODE_LABEL
!= GET_CODE (label
)) abort ();
330 lp
= mvs_get_label (labelno
);
331 if (-1 == lp
-> first_ref_page
) lp
->first_ref_page
= mvs_page_num
;
337 i370_branch_length (insn
)
341 here
= insn_addresses
[INSN_UID (insn
)];
342 there
= i370_branch_dest (insn
);
343 return (there
- here
);
348 i370_short_branch (insn
)
353 base_offset
= i370_branch_length(insn
);
356 base_offset
+= mvs_page_code
;
360 /* avoid bumping into lit pool; use 2x to estimate max possible lits */
362 base_offset
+= mvs_page_code
+ mvs_page_lit
;
365 /* make a conservative estimate of room left on page */
366 if ((4060 >base_offset
) && ( 0 < base_offset
)) return 1;
370 /* The i370_label_scan() routine is supposed to loop over
371 all labels and label references in a compilation unit,
372 and determine whether all label refs appear on the same
373 code page as the label. If they do, then we can avoid
374 a reload of the base register for that label.
376 Note that the instruction addresses used here are only
377 approximate, and make the sizes of the jumps appear
378 farther apart then they will actually be. This makes
379 this code far more conservative than it needs to be.
382 #define I370_RECORD_LABEL_REF(label,addr) { \
384 int labelno = CODE_LABEL_NUMBER (label); \
385 lp = mvs_get_label (labelno); \
386 if (addr < lp -> label_first_ref) lp->label_first_ref = addr; \
387 if (addr > lp -> label_last_ref) lp->label_last_ref = addr; \
391 i370_label_scan (void)
395 int tablejump_offset
= 0;
397 for (insn
= get_insns(); insn
; insn
= NEXT_INSN(insn
))
399 int here
= insn_addresses
[INSN_UID (insn
)];
400 enum rtx_code code
= GET_CODE(insn
);
402 /* ??? adjust for tables embedded in the .text section that
403 * the compiler didn't take into account */
404 here
+= tablejump_offset
;
405 insn_addresses
[INSN_UID (insn
)] = here
;
407 /* check to see if this insn is a label ... */
408 if (CODE_LABEL
== code
)
410 int labelno
= CODE_LABEL_NUMBER (insn
);
412 lp
= mvs_get_label (labelno
);
413 lp
-> label_addr
= here
;
415 /* Supposedly, labels are supposed to have circular
416 lists of label-refs that reference them,
417 setup in flow.c, but this does not appear to be the case. */
418 rtx labelref
= LABEL_REFS (insn
);
422 rtx linsn
= CONTAINING_INSN(ref
);
423 ref
= LABEL_NEXTREF(ref
);
424 } while (ref
&& (ref
!= labelref
));
428 if (JUMP_INSN
== code
)
430 rtx label
= JUMP_LABEL (insn
);
433 /* If there is no label for this jump, then this
434 had better be a ADDR_VEC or an ADDR_DIFF_VEC
435 and there had better be a vector of labels. */
439 rtx body
= PATTERN (insn
);
440 if (ADDR_VEC
== GET_CODE(body
))
442 for (j
=0; j
< XVECLEN (body
, 0); j
++)
445 rtx lref
= XVECEXP (body
, 0, j
);
446 if (LABEL_REF
!= GET_CODE (lref
)) abort ();
447 label
= XEXP (lref
,0);
448 if (CODE_LABEL
!= GET_CODE (label
)) abort ();
449 tablejump_offset
+= 4;
451 I370_RECORD_LABEL_REF(label
,here
);
453 /* finished with the vector go do next insn */
457 if (ADDR_DIFF_VEC
== GET_CODE(body
))
460 Right now, we leave this as a no-op, but strictly speaking,
461 this is incorrect. It is possible that a table-jump
462 driven off of a relative address could take us off-page,
463 to a place where we need to reload the base reg. So really,
464 we need to examing both labels, and compare thier values
465 to the current basereg value.
467 More generally, this brings up a troubling issue overall:
468 what happens if a tablejump is split across two pages? I do
469 not beleive that this case is handled correctly at all, and
470 can only lead to horrible results if this were to occur.
472 However, the current situation is not any worse than it was
473 last week, and so we punt for now. */
477 for (j
=0; j
< XVECLEN (body
, 0); j
++)
481 /* finished with the vector go do next insn */
487 Compiling the execption handling (L_eh) in libgcc2.a will trip
488 up right here, with something that looks like
489 (set (pc) (mem:SI (plus:SI (reg/v:SI 1 r1) (const_int 4))))
491 I'm not sure of what leads up to this, but it looks like
492 the makings of a long jump which will surely get us into trouble
493 because the base & page registers don't get reloaded. For now
494 I'm not sure of what to do ... again we punt ... we are not worse
495 off than yesterday. */
497 /* print_rtl_single (stdout, insn); */
505 /* At this point, this jump_insn had better be a plain-old
506 ordinary one, grap the label id and go */
507 if (CODE_LABEL
!= GET_CODE (label
)) abort ();
508 I370_RECORD_LABEL_REF(label
,here
);
512 /* Sometimes, we take addresses of labels and use them
513 as instruction operands ... these show up as REG_NOTES */
517 if ('i' == GET_RTX_CLASS (code
))
520 for (note
= REG_NOTES (insn
); note
; note
= XEXP(note
,1))
522 if (REG_LABEL
== REG_NOTE_KIND(note
))
524 rtx label
= XEXP (note
,0);
525 if (!label
|| CODE_LABEL
!= GET_CODE (label
)) abort ();
527 I370_RECORD_LABEL_REF(label
,here
);
535 /* ===================================================== */
537 /* Emit reload of base register if indicated. This is to eliminate multiple
538 reloads when several labels are generated pointing to the same place
541 The page table is written at the end of the function.
542 The entries in the page table look like
543 .LPGT0: // PGT0 EQU *
544 .long .LPG0 // DC A(PG0)
545 .long .LPG1 // DC A(PG1)
546 while the prologue generates
549 Note that this paging scheme breaks down if a single subroutine
550 has more than about 10MB of code in it ... as long as humans write
551 code, this shouldn't be a problem ...
555 check_label_emit (void)
557 if (mvs_need_base_reload
)
559 mvs_need_base_reload
= 0;
562 fprintf (assembler_source
, "\tL\t%d,%d(,%d)\n",
563 BASE_REGISTER
, (mvs_page_num
- function_base_page
) * 4,
568 /* Add the label to the current page label list. If a free element is available
569 it will be used for the new label. Otherwise, a label element will be
570 allocated from memory.
571 ID is the label number of the label being added to the list. */
579 /* first, lets see if we already go one, if so, use that. */
580 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
582 if (lp
->label_id
== id
) return lp
;
585 /* not found, get a new one */
589 free_anchor
= lp
->label_next
;
593 lp
= (label_node_t
*) xmalloc (sizeof (label_node_t
));
596 /* initialize for new label */
599 lp
->label_next
= label_anchor
;
600 lp
->label_first_ref
= 2000123123;
601 lp
->label_last_ref
= -1;
603 lp
->first_ref_page
= -1;
616 lp
= mvs_get_label (id
);
617 lp
->label_page
= mvs_page_num
;
619 /* OK, we just saw the label. Determine if this label
620 * needs a reload of the base register */
621 if ((-1 != lp
->first_ref_page
) &&
622 (lp
->first_ref_page
!= mvs_page_num
))
624 /* Yep; the first label_ref was on a different page. */
625 mvs_need_base_reload
++;
629 /* Hmm. Try to see if the estimated address of the last
630 label_ref is on the current page. If it is, then we
631 don't need a base reg reload. Note that this estimate
632 is very conservatively handled; we'll tend to have
633 a good bit more reloads than actually needed. Someday,
634 we should tighten the estimates (which are driven by
635 the (set_att "length") insn attibute.
637 Currently, we estimate that number of page literals
638 same as number of insns, which is a vast overestimate,
639 esp that the estimate of each insn size is its max size. */
641 /* if latest ref comes before label, we are clear */
642 if (lp
->label_last_ref
< lp
->label_addr
) return;
644 fwd_distance
= lp
->label_last_ref
- lp
->label_addr
;
646 if (mvs_page_code
+ 2*fwd_distance
+ mvs_page_lit
< 4060) return;
648 mvs_need_base_reload
++;
651 /* Check to see if the label is in the list and in the current
652 page. If not found, we have to make worst case assumption
653 that label will be on a different page, and thus will have to
654 generate a load and branch on register. This is rather
655 ugly for forward-jumps, but what can we do? For backward
656 jumps on the same page we can branch directly to address.
657 ID is the label number of the label being checked. */
665 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
667 if (lp
->label_id
== id
)
669 if (lp
->label_page
== mvs_page_num
)
682 /* Get the page on which the label sits. This will be used to
683 determine is a register reload is really needed. */
686 mvs_get_label_page(int id
)
690 for (lp
= label_anchor
; lp
; lp
= lp
->label_next
)
692 if (lp
->label_id
== id
)
693 return lp
->label_page
;
698 /* The label list for the current page freed by linking the list onto the free
699 label element chain. */
702 mvs_free_label_list (void)
707 label_node_t
*last_lp
= label_anchor
;
708 while (last_lp
->label_next
) last_lp
= last_lp
->label_next
;
709 last_lp
->label_next
= free_anchor
;
710 free_anchor
= label_anchor
;
715 /* ====================================================================== */
716 /* If the page size limit is reached a new code page is started, and the base
717 register is set to it. This page break point is counted conservatively,
718 most literals that have the same value are collapsed by the assembler.
719 True is returned when a new page is started.
720 FILE is the assembler output file descriptor.
721 CODE is the length, in bytes, of the instruction to be emitted.
722 LIT is the length of the literal to be emitted. */
726 mvs_check_page (file
, code
, lit
)
731 assembler_source
= file
;
733 if (mvs_page_code
+ code
+ mvs_page_lit
+ lit
> MAX_MVS_PAGE_LENGTH
)
735 fprintf (assembler_source
, "\tB\tPGE%d\n", mvs_page_num
);
736 fprintf (assembler_source
, "\tDS\t0F\n");
737 fprintf (assembler_source
, "\tLTORG\n");
738 fprintf (assembler_source
, "\tDS\t0F\n");
739 fprintf (assembler_source
, "PGE%d\tEQU\t*\n", mvs_page_num
);
740 fprintf (assembler_source
, "\tDROP\t%d\n", BASE_REGISTER
);
742 /* Safe to use BASR not BALR, since we are
743 * not switching addressing mode here ... */
744 fprintf (assembler_source
, "\tBASR\t%d,0\n", BASE_REGISTER
);
745 fprintf (assembler_source
, "PG%d\tEQU\t*\n", mvs_page_num
);
746 fprintf (assembler_source
, "\tUSING\t*,%d\n", BASE_REGISTER
);
747 mvs_page_code
= code
;
751 mvs_page_code
+= code
;
755 #endif /* TARGET_HLASM */
758 #ifdef TARGET_ELF_ABI
760 mvs_check_page (file
, code
, lit
)
765 assembler_source
= file
;
767 if (mvs_page_code
+ code
+ mvs_page_lit
+ lit
> MAX_MVS_PAGE_LENGTH
)
769 /* hop past the literal pool */
770 fprintf (assembler_source
, "\tB\t.LPGE%d\n", mvs_page_num
);
772 /* dump the literal pool. The .baligns are optional, since
773 * ltorg will align to the size of the largest literal
774 * (which is possibly 8 bytes) */
775 fprintf (assembler_source
, "\t.balign\t4\n");
776 fprintf (assembler_source
, "\t.LTORG\n");
777 fprintf (assembler_source
, "\t.balign\t4\n");
779 /* we continue execution here ... */
780 fprintf (assembler_source
, ".LPGE%d:\n", mvs_page_num
);
781 fprintf (assembler_source
, "\t.DROP\t%d\n", BASE_REGISTER
);
784 /* BASR puts the contents of the PSW into r3
785 * that is, r3 will be loaded with the address of "." */
786 fprintf (assembler_source
, "\tBASR\tr%d,0\n", BASE_REGISTER
);
787 fprintf (assembler_source
, ".LPG%d:\n", mvs_page_num
);
788 fprintf (assembler_source
, "\t.USING\t.,r%d\n", BASE_REGISTER
);
789 mvs_page_code
= code
;
793 mvs_page_code
+= code
;
797 #endif /* TARGET_ELF_ABI */
799 /* ===================================================== */
800 /* defines and functions specific to the HLASM assembler */
803 /* Check for C/370 runtime function, they don't use standard calling
804 conventions. True is returned if the function is in the table.
805 NAME is the name of the current function. */
808 mvs_function_check (name
)
811 int lower
, middle
, upper
;
815 upper
= MVS_FUNCTION_TABLE_LENGTH
- 1;
816 while (lower
<= upper
)
818 middle
= (lower
+ upper
) / 2;
819 i
= strcmp (name
, mvs_function_table
[middle
]);
831 /* Add the alias to the current alias list. */
834 mvs_add_alias (realname
, aliasname
, emitted
)
841 ap
= (alias_node_t
*) xmalloc (sizeof (alias_node_t
));
842 strcpy (ap
->real_name
, realname
);
843 strcpy (ap
->alias_name
, aliasname
);
844 ap
->alias_emitted
= emitted
;
845 ap
->alias_next
= alias_anchor
;
849 /* Check to see if the name needs aliasing */
852 mvs_need_alias (realname
)
855 if (mvs_function_check (realname
))
857 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
859 if (strchr (realname
, '_') != 0)
864 /* Get the alias from the list.
865 If 1 is returned then it's in the alias list, 0 if it was not */
868 mvs_get_alias (realname
, aliasname
)
875 for (ap
= alias_anchor
; ap
; ap
= ap
->alias_next
)
877 if (!strcmp (ap
->real_name
, realname
))
879 strcpy (aliasname
, ap
->alias_name
);
883 if (mvs_need_alias (realname
))
885 sprintf (aliasname
, "ALS%05d", alias_number
++);
886 mvs_add_alias (realname
, aliasname
, 0);
890 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
892 strncpy (aliasname
, realname
, MAX_MVS_LABEL_SIZE
);
893 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
900 /* Check to see if the alias is in the list.
901 If 1 is returned then it's in the alias list, 2 it was emitted */
904 mvs_check_alias (realname
, aliasname
)
911 for (ap
= alias_anchor
; ap
; ap
= ap
->alias_next
)
913 if (!strcmp (ap
->real_name
, realname
))
915 int rc
= (ap
->alias_emitted
== 1) ? 1 : 2;
916 strcpy (aliasname
, ap
->alias_name
);
917 ap
->alias_emitted
= 1;
921 if (mvs_need_alias (realname
))
923 sprintf (aliasname
, "ALS%05d", alias_number
++);
924 mvs_add_alias (realname
, aliasname
, 0);
925 alias_anchor
->alias_emitted
= 1;
929 if (strlen (realname
) > MAX_MVS_LABEL_SIZE
)
931 strncpy (aliasname
, realname
, MAX_MVS_LABEL_SIZE
);
932 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
939 /* Called from check_newline via the macro HANDLE_PRAGMA.
940 FINPUT is the source file input stream.
941 NODE is the tree node for the token after the "pragma".
942 The result is 1 if the pragma was handled. */
945 handle_pragma (finput
, node
)
951 register char *pname
;
953 if (TREE_CODE (node
) != IDENTIFIER_NODE
)
956 pname
= IDENTIFIER_POINTER (node
);
958 if (strcmp (pname
, "map") == 0)
960 char realname
[MAX_LONG_LABEL_SIZE
+ 1];
961 char aliasname
[MAX_MVS_LABEL_SIZE
+ 1];
966 } while (c
== ' ' || c
== '\t');
973 } while (c
== ' ' || c
== '\t');
979 } while (isalnum(c
) || c
== '_');
984 if (c
== ' ' || c
== '\t')
987 } while (c
== ' ' || c
== '\t');
993 } while (c
== ' ' || c
== '\t');
1004 if (c
>= '0' && c
<= '7')
1005 d
= (d
<< 3) | c
- '0';
1006 } while (c
>= '0' && c
<= '7');
1009 if (d
< 1 || d
> 255)
1010 warning ("Escape value out of range");
1017 if (isspace(c
) || c
== ')')
1018 goto PRAGMA_WARNING
;
1021 if (strlen (aliasname
) > MAX_MVS_LABEL_SIZE
)
1023 warning ("#pragma map alias is too long, truncated");
1024 aliasname
[MAX_MVS_LABEL_SIZE
] = '\0';
1028 } while (c
== ' ' || c
== '\t');
1031 mvs_add_alias (realname
, aliasname
, 1);
1035 goto PRAGMA_WARNING
;
1038 goto PRAGMA_WARNING
;
1041 goto PRAGMA_WARNING
;
1047 warning ("#pragma map options are missing or incorrect");
1055 /* defines and functions specific to the HLASM assembler */
1056 #endif /* TARGET_HLASM */
1057 /* ===================================================== */
1058 /* ===================================================== */
1059 /* defines and functions specific to the gas assembler */
1060 #ifdef TARGET_ELF_ABI
1062 /* Check for C/370 runtime function, they don't use standard calling
1063 conventions. True is returned if the function is in the table.
1064 NAME is the name of the current function. */
1065 /* no special calling conventions (yet ??) */
1068 mvs_function_check (name
)
1074 #endif /* TARGET_ELF_ABI */
1075 /* ===================================================== */
1078 /* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
1079 OP is the current operation.
1080 MODE is the current operation mode. */
1083 s_operand (op
, mode
)
1085 enum machine_mode mode
;
1087 extern int volatile_ok
;
1088 register enum rtx_code code
= GET_CODE (op
);
1090 if (CONSTANT_ADDRESS_P (op
))
1092 if (mode
== VOIDmode
|| GET_MODE (op
) != mode
)
1096 register rtx x
= XEXP (op
, 0);
1098 if (!volatile_ok
&& op
->volatil
)
1100 if (REG_P (x
) && REG_OK_FOR_BASE_P (x
))
1102 if (GET_CODE (x
) == PLUS
1103 && REG_P (XEXP (x
, 0)) && REG_OK_FOR_BASE_P (XEXP (x
, 0))
1104 && GET_CODE (XEXP (x
, 1)) == CONST_INT
1105 && (unsigned) INTVAL (XEXP (x
, 1)) < 4096)
1112 /* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
1114 OP is the current operation.
1115 MODE is the current operation mode. */
1118 r_or_s_operand (op
, mode
)
1120 enum machine_mode mode
;
1122 extern int volatile_ok
;
1123 register enum rtx_code code
= GET_CODE (op
);
1125 if (CONSTANT_ADDRESS_P (op
))
1127 if (mode
== VOIDmode
|| GET_MODE (op
) != mode
)
1131 else if (code
== MEM
)
1133 register rtx x
= XEXP (op
, 0);
1135 if (!volatile_ok
&& op
->volatil
)
1137 if (REG_P (x
) && REG_OK_FOR_BASE_P (x
))
1139 if (GET_CODE (x
) == PLUS
1140 && REG_P (XEXP (x
, 0)) && REG_OK_FOR_BASE_P (XEXP (x
, 0))
1141 && GET_CODE (XEXP (x
, 1)) == CONST_INT
1142 && (unsigned) INTVAL (XEXP (x
, 1)) < 4096)
1149 /* Some remarks about unsigned_jump_follows_p():
1150 gcc is built around the assumption that branches are signed
1151 or unsigned, whereas the 370 doesn't care; its the compares that
1152 are signed or unsigned. Thus, we need to somehow know if we
1153 need to do a signed or an unsigned compare, and we do this by
1154 looking ahead in the instruction sequence until we find a jump.
1155 We then note whether this jump is signed or unsigned, and do the
1156 compare appropriately. Note that we have to scan ahead indefinitley,
1157 as the gcc optimizer may insert any number of instructions between
1158 the compare and the jump.
1160 Note that using conditional branch expanders seems to be be a more
1161 elegant/correct way of doing this. See, for instance, the Alpha
1162 cmpdi and bgt patterns. Note also that for the i370, various
1163 arithmetic insn's set the condition code as well.
1165 The unsigned_jump_follows_p() routine returns a 1 if the next jump
1166 is unsigned. INSN is the current instruction. */
1168 unsigned_jump_follows_p (insn
)
1171 rtx orig_insn
= insn
;
1174 register rtx tmp_insn
;
1177 insn
= NEXT_INSN (insn
);
1178 if (!insn
) fatal_insn ("internal error--no jump follows compare:", orig_insn
);
1180 if (GET_CODE (insn
) != JUMP_INSN
) continue;
1182 tmp_insn
= XEXP (insn
, 3);
1183 if (GET_CODE (tmp_insn
) != SET
) continue;
1185 if (GET_CODE (XEXP (tmp_insn
, 0)) != PC
) continue;
1187 tmp_insn
= XEXP (tmp_insn
, 1);
1188 if (GET_CODE (tmp_insn
) != IF_THEN_ELSE
) continue;
1190 /* if we got to here, this instruction is a jump. Is it signed? */
1191 tmp_insn
= XEXP (tmp_insn
, 0);
1192 coda
= GET_CODE (tmp_insn
);
1194 return coda
!= GE
&& coda
!= GT
&& coda
!= LE
&& coda
!= LT
;
1202 i370_function_prolog (f
, l
)
1206 #if MACROPROLOGUE == 1
1207 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1208 fprintf (f
, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
1209 STACK_POINTER_OFFSET
+ l
- 120 +
1210 current_function_outgoing_args_size
, BASE_REGISTER
);
1211 #else /* MACROPROLOGUE != 1 */
1212 static int function_label_index
= 1;
1213 static int function_first
= 0;
1214 static int function_year
, function_month
, function_day
;
1215 static int function_hour
, function_minute
, function_second
;
1218 if (!function_first
)
1220 struct tm
*function_time
;
1223 function_time
= localtime (&lcltime
);
1224 function_year
= function_time
->tm_year
+ 1900;
1225 function_month
= function_time
->tm_mon
+ 1;
1226 function_day
= function_time
->tm_mday
;
1227 function_hour
= function_time
->tm_hour
;
1228 function_minute
= function_time
->tm_min
;
1229 function_second
= function_time
->tm_sec
;
1231 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1232 fprintf (f
, "FDSE%03d\tDSECT\n", function_label_index
);
1233 fprintf (f
, "\tDS\tD\n");
1234 fprintf (f
, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET
+ l
1235 + current_function_outgoing_args_size
);
1236 fprintf (f
, "\tORG\tFDSE%03d\n", function_label_index
);
1237 fprintf (f
, "\tDS\tCL(120+8)\n");
1238 fprintf (f
, "\tORG\n");
1239 fprintf (f
, "\tDS\t0D\n");
1240 fprintf (f
, "FDSL%03d\tEQU\t*-FDSE%03d-8\n", function_label_index
,
1241 function_label_index
);
1242 fprintf (f
, "\tDS\t0H\n");
1243 assemble_name (f
, mvs_function_name
);
1244 fprintf (f
, "\tCSECT\n");
1245 fprintf (f
, "\tUSING\t*,15\n");
1246 fprintf (f
, "\tB\tFENT%03d\n", function_label_index
);
1247 fprintf (f
, "\tDC\tAL1(FNAM%03d+4-*)\n", function_label_index
);
1248 fprintf (f
, "\tDC\tX'CE',X'A0',AL1(16)\n");
1249 fprintf (f
, "\tDC\tAL4(FPPA%03d)\n", function_label_index
);
1250 fprintf (f
, "\tDC\tAL4(0)\n");
1251 fprintf (f
, "\tDC\tAL4(FDSL%03d)\n", function_label_index
);
1252 fprintf (f
, "FNAM%03d\tEQU\t*\n", function_label_index
);
1253 fprintf (f
, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name
),
1255 fprintf (f
, "FPPA%03d\tDS\t0F\n", function_label_index
);
1256 fprintf (f
, "\tDC\tX'03',X'00',X'33',X'00'\n");
1257 fprintf (f
, "\tDC\tV(CEESTART)\n");
1258 fprintf (f
, "\tDC\tAL4(0)\n");
1259 fprintf (f
, "\tDC\tAL4(FTIM%03d)\n", function_label_index
);
1260 fprintf (f
, "FTIM%03d\tDS\t0F\n", function_label_index
);
1261 fprintf (f
, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1262 function_year
, function_month
, function_day
,
1263 function_hour
, function_minute
, function_second
);
1264 fprintf (f
, "\tDC\tCL2'01',CL4'0100'\n");
1265 fprintf (f
, "FENT%03d\tDS\t0H\n", function_label_index
);
1266 fprintf (f
, "\tSTM\t14,12,12(13)\n");
1267 fprintf (f
, "\tL\t2,76(,13)\n");
1268 fprintf (f
, "\tL\t0,16(,15)\n");
1269 fprintf (f
, "\tALR\t0,2\n");
1270 fprintf (f
, "\tCL\t0,12(,12)\n");
1271 fprintf (f
, "\tBNH\t*+10\n");
1272 fprintf (f
, "\tL\t15,116(,12)\n");
1273 fprintf (f
, "\tBALR\t14,15\n");
1274 fprintf (f
, "\tL\t15,72(,13)\n");
1275 fprintf (f
, "\tSTM\t15,0,72(2)\n");
1276 fprintf (f
, "\tMVI\t0(2),X'10'\n");
1277 fprintf (f
, "\tST\t2,8(,13)\n ");
1278 fprintf (f
, "\tST\t13,4(,2)\n ");
1279 fprintf (f
, "\tLR\t13,2\n");
1280 fprintf (f
, "\tDROP\t15\n");
1281 fprintf (f
, "\tBALR\t%d,0\n", BASE_REGISTER
);
1282 fprintf (f
, "\tUSING\t*,%d\n", BASE_REGISTER
);
1284 function_label_index
++;
1286 if (!function_first
)
1288 struct tm
*function_time
;
1291 function_time
= localtime (&lcltime
);
1292 function_year
= function_time
->tm_year
+ 1900;
1293 function_month
= function_time
->tm_mon
+ 1;
1294 function_day
= function_time
->tm_mday
;
1295 function_hour
= function_time
->tm_hour
;
1296 function_minute
= function_time
->tm_min
;
1297 function_second
= function_time
->tm_sec
;
1298 fprintf (f
, "PPA2\tDS\t0F\n");
1299 fprintf (f
, "\tDC\tX'03',X'00',X'33',X'00'\n");
1300 fprintf (f
, "\tDC\tV(CEESTART),A(0)\n");
1301 fprintf (f
, "\tDC\tA(CEETIMES)\n");
1302 fprintf (f
, "CEETIMES\tDS\t0F\n");
1303 fprintf (f
, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
1304 function_year
, function_month
, function_day
,
1305 function_hour
, function_minute
, function_second
);
1306 fprintf (f
, "\tDC\tCL2'01',CL4'0100'\n");
1308 fprintf (f
, "* Function %s prologue\n", mvs_function_name
);
1309 fprintf (f
, "FDSD%03d\tDSECT\n", function_label_index
);
1310 fprintf (f
, "\tDS\tD\n");
1311 fprintf (f
, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET
+ l
1312 + current_function_outgoing_args_size
);
1313 fprintf (f
, "\tORG\tFDSD%03d\n", function_label_index
);
1314 fprintf (f
, "\tDS\tCL(120+8)\n");
1315 fprintf (f
, "\tORG\n");
1316 fprintf (f
, "\tDS\t0D\n");
1317 fprintf (f
, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index
,
1318 function_label_index
);
1319 fprintf (f
, "\tDS\t0H\n");
1320 assemble_name (f
, mvs_function_name
);
1321 fprintf (f
, "\tCSECT\n");
1322 fprintf (f
, "\tUSING\t*,15\n");
1323 fprintf (f
, "\tB\tFPL%03d\n", function_label_index
);
1324 fprintf (f
, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index
+ 1);
1325 fprintf (f
, "\tDC\tX'CE',X'A0',AL1(16)\n");
1326 fprintf (f
, "\tDC\tAL4(PPA2)\n");
1327 fprintf (f
, "\tDC\tAL4(0)\n");
1328 fprintf (f
, "\tDC\tAL4(FDSL%03d)\n", function_label_index
);
1329 fprintf (f
, "FPL%03d\tEQU\t*\n", function_label_index
+ 1);
1330 fprintf (f
, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name
),
1332 fprintf (f
, "FPL%03d\tDS\t0H\n", function_label_index
);
1333 fprintf (f
, "\tSTM\t14,12,12(13)\n");
1334 fprintf (f
, "\tL\t2,76(,13)\n");
1335 fprintf (f
, "\tL\t0,16(,15)\n");
1336 fprintf (f
, "\tALR\t0,2\n");
1337 fprintf (f
, "\tCL\t0,12(,12)\n");
1338 fprintf (f
, "\tBNH\t*+10\n");
1339 fprintf (f
, "\tL\t15,116(,12)\n");
1340 fprintf (f
, "\tBALR\t14,15\n");
1341 fprintf (f
, "\tL\t15,72(,13)\n");
1342 fprintf (f
, "\tSTM\t15,0,72(2)\n");
1343 fprintf (f
, "\tMVI\t0(2),X'10'\n");
1344 fprintf (f
, "\tST\t2,8(,13)\n ");
1345 fprintf (f
, "\tST\t13,4(,2)\n ");
1346 fprintf (f
, "\tLR\t13,2\n");
1347 fprintf (f
, "\tDROP\t15\n");
1348 fprintf (f
, "\tBALR\t%d,0\n", BASE_REGISTER
);
1349 fprintf (f
, "\tUSING\t*,%d\n", BASE_REGISTER
);
1351 function_label_index
+= 2;
1353 #endif /* MACROPROLOGUE */
1354 fprintf (f
, "PG%d\tEQU\t*\n", mvs_page_num
);
1355 fprintf (f
, "\tLR\t11,1\n");
1356 fprintf (f
, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER
, mvs_page_num
);
1357 fprintf (f
, "* Function %s code\n", mvs_function_name
);
1359 mvs_free_label_list ();
1362 mvs_check_page (f
, 0, 0);
1363 function_base_page
= mvs_page_num
;
1365 /* find all labels in this routine */
1368 #endif /* TARGET_HLASM */
1371 #ifdef TARGET_ELF_ABI
1373 The 370_function_prolog() routine generates the current ELF ABI ES/390 prolog.
1374 It implements a stack that grows downward.
1375 It performs the following steps:
1376 -- saves the callers non-volatile registers on the callers stack.
1377 -- subtracts stackframe size from the stack pointer.
1378 -- stores backpointer to old caller stack.
1380 XXX hack alert -- if the global var int leaf_function is non-zero,
1381 then this is a leaf, and it might be possible to optimize the prologue
1382 into doing even less, e.g. not grabbing a new stackframe or maybe just a
1383 partial stack frame.
1385 XXX hack alert -- the current stack frame is bloated into twice the
1386 needed size by unused entries. These entries make it marginally
1387 compatible with MVS/OE/USS C environment, but really they're not used
1388 and could probably chopped out. Modifications to i370.md would be needed
1389 also, to quite using addresses 136, 140, etc.
1393 i370_function_prolog (f
, frame_size
)
1397 static int function_label_index
= 1;
1398 static int function_first
= 0;
1400 int stackframe_size
, soffset
, aligned_size
;
1402 fprintf (f
, "# Function prologue\n");
1403 /* define the stack, put it into its own data segment
1404 FDSE == Function Stack Entry
1405 FDSL == Function Stack Length */
1407 STACK_POINTER_OFFSET
+ current_function_outgoing_args_size
+ frame_size
;
1408 aligned_size
= (stackframe_size
+ 7) >> 3;
1411 fprintf (f
, "# arg_size=0x%x frame_size=0x%x aligned size=0x%x\n",
1412 current_function_outgoing_args_size
, frame_size
, aligned_size
);
1414 fprintf (f
, "\t.using\t.,r15\n");
1416 /* Branch to exectuable part of prologue. */
1417 fprintf (f
, "\tB\t.LFENT%03d\n", function_label_index
);
1419 /* write the length of the stackframe */
1420 fprintf (f
, "\t.long\t%d\n", aligned_size
);
1422 /* FENT == function prologue entry */
1423 fprintf (f
, "\t.balign 2\n.LFENT%03d:\n",
1424 function_label_index
);
1426 /* store multiple registers 14,15,0,...12 at 12 bytes from sp */
1427 fprintf (f
, "\tSTM\tr14,r12,12(sp)\n");
1429 /* r3 == saved callee stack pointer */
1430 fprintf (f
, "\tLR\tr3,sp\n");
1432 /* 4(r15) == stackframe size */
1433 fprintf (f
, "\tSL\tsp,4(,r15)\n");
1435 /* r11 points to arg list in callers stackframe; was passed in r2 */
1436 fprintf (f
, "\tLR\tr11,r2\n");
1438 /* store callee stack pointer at 8(sp) */
1439 /* fprintf (f, "\tST\tsp,8(,r3)\n "); wasted cycles, no one uses this ... */
1441 /* backchain -- store caller sp at 4(callee_sp) */
1442 fprintf (f
, "\tST\tr3,4(,sp)\n ");
1444 fprintf (f
, "\t.drop\tr15\n");
1445 /* Place contents of the PSW into r3
1446 that is, place the address of "." into r3 */
1447 fprintf (f
, "\tBASR\tr%d,0\n", BASE_REGISTER
);
1448 fprintf (f
, "\t.using\t.,r%d\n", BASE_REGISTER
);
1450 function_label_index
++;
1452 fprintf (f
, ".LPG%d:\n", mvs_page_num
);
1453 fprintf (f
, "\tL\tr%d,=A(.LPGT%d)\n", PAGE_REGISTER
, mvs_page_num
);
1454 fprintf (f
, "# Function code\n");
1456 mvs_free_label_list ();
1459 mvs_check_page (f
, 0, 0);
1460 function_base_page
= mvs_page_num
;
1462 /* find all labels in this routine */
1465 #endif /* TARGET_ELF_ABI */