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