]>
Commit | Line | Data |
---|---|---|
f2423e19 | 1 | /* Subroutines for insn-output.c for System/370. |
c5c76735 | 2 | Copyright (C) 1989, 93, 95, 97, 98, 1999 Free Software Foundation, Inc. |
f2423e19 | 3 | Contributed by Jan Stein (jan@cd.chalmers.se). |
92d6db66 LV |
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) | |
f2423e19 PE |
6 | |
7 | This file is part of GNU CC. | |
8 | ||
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) | |
12 | any later version. | |
13 | ||
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. | |
18 | ||
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. */ | |
23 | ||
a0d66c8d | 24 | #include "config.h" |
c5c76735 | 25 | #include "system.h" |
f2423e19 | 26 | #include "rtl.h" |
92d6db66 | 27 | #include "tree.h" |
f2423e19 PE |
28 | #include "regs.h" |
29 | #include "hard-reg-set.h" | |
30 | #include "real.h" | |
31 | #include "insn-config.h" | |
32 | #include "conditions.h" | |
33 | #include "insn-flags.h" | |
34 | #include "output.h" | |
35 | #include "insn-attr.h" | |
ff9350e7 | 36 | /* #include "function.h" */ |
f2423e19 PE |
37 | #include "flags.h" |
38 | #include "recog.h" | |
39 | ||
92d6db66 LV |
40 | extern FILE *asm_out_file; |
41 | ||
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. */ | |
f2423e19 | 50 | |
f2423e19 PE |
51 | typedef struct label_node |
52 | { | |
53 | struct label_node *label_next; | |
54 | int label_id; | |
55 | int label_page; | |
92d6db66 LV |
56 | int first_ref_page; |
57 | ||
58 | int label_addr; | |
59 | int label_first_ref; | |
60 | int label_last_ref; | |
f2423e19 PE |
61 | } |
62 | label_node_t; | |
63 | ||
92d6db66 LV |
64 | /* Is 1 when a label has been generated and the base register must be reloaded. */ |
65 | int mvs_need_base_reload = 0; | |
f2423e19 PE |
66 | |
67 | /* Current function starting base page. */ | |
68 | int function_base_page; | |
69 | ||
70 | /* Length of the current page code. */ | |
71 | int mvs_page_code; | |
72 | ||
73 | /* Length of the current page literals. */ | |
74 | int mvs_page_lit; | |
75 | ||
76 | /* Current function name. */ | |
77 | char *mvs_function_name = 0; | |
78 | ||
79 | /* Current function name length. */ | |
80 | int mvs_function_name_length = 0; | |
81 | ||
82 | /* Page number for multi-page functions. */ | |
83 | int mvs_page_num = 0; | |
84 | ||
85 | /* Label node list anchor. */ | |
86 | static label_node_t *label_anchor = 0; | |
87 | ||
88 | /* Label node free list anchor. */ | |
89 | static label_node_t *free_anchor = 0; | |
90 | ||
91 | /* Assembler source file descriptor. */ | |
92 | static FILE *assembler_source = 0; | |
93 | ||
92d6db66 LV |
94 | label_node_t * mvs_get_label (); |
95 | ||
96 | /* ===================================================== */ | |
97 | /* defines and functions specific to the HLASM assembler */ | |
98 | #ifdef TARGET_HLASM | |
99 | ||
100 | #ifndef MAX_MVS_LABEL_SIZE | |
101 | #define MAX_MVS_LABEL_SIZE 8 | |
102 | #endif | |
103 | ||
104 | #define MAX_LONG_LABEL_SIZE 255 | |
105 | ||
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 | |
111 | { | |
112 | struct alias_node *alias_next; | |
113 | int alias_emitted; | |
114 | char alias_name [MAX_MVS_LABEL_SIZE + 1]; | |
115 | char real_name [MAX_LONG_LABEL_SIZE + 1]; | |
116 | } | |
117 | alias_node_t; | |
118 | ||
119 | /* Alias node list anchor. */ | |
120 | static alias_node_t *alias_anchor = 0; | |
121 | ||
122 | /* Alias number */ | |
123 | static alias_number = 0; | |
124 | ||
f2423e19 PE |
125 | /* Define the length of the internal MVS function table. */ |
126 | #define MVS_FUNCTION_TABLE_LENGTH 32 | |
127 | ||
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] = | |
131 | { | |
92d6db66 LV |
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", | |
138 | "y0", "y1" | |
139 | #else | |
f2423e19 PE |
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", | |
145 | "y1", "yn" | |
92d6db66 | 146 | #endif |
f2423e19 PE |
147 | }; |
148 | ||
92d6db66 LV |
149 | #endif /* TARGET_HLASM */ |
150 | /* ===================================================== */ | |
151 | ||
f2423e19 | 152 | /* ASCII to EBCDIC conversion table. */ |
f2423e19 PE |
153 | static unsigned char ascebc[256] = |
154 | { | |
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 | |
203 | }; | |
f2423e19 PE |
204 | |
205 | /* EBCDIC to ASCII conversion table. */ | |
f2423e19 PE |
206 | unsigned char ebcasc[256] = |
207 | { | |
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, | |
222 | /*38 C3 D4 NK SU */ | |
223 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A, | |
224 | /*40 SP */ | |
225 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
226 | /*48 . < ( + | */ | |
227 | 0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, | |
228 | /*50 & */ | |
229 | 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
230 | /*58 ! $ * ) ; ^ */ | |
231 | 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, | |
232 | /*60 - / */ | |
233 | 0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
234 | /*68 , % _ > ? */ | |
235 | 0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, | |
236 | /*70 */ | |
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, | |
242 | /*88 h i { */ | |
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, | |
246 | /*98 q r } */ | |
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, | |
250 | /*A8 y z [ */ | |
251 | 0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, | |
252 | /*B0 */ | |
253 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
254 | /*B8 ] */ | |
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, | |
258 | /*C8 H I */ | |
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, | |
262 | /*D8 Q R */ | |
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, | |
266 | /*E8 Y Z */ | |
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, | |
270 | /*F8 8 9 */ | |
271 | 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF | |
272 | }; | |
f2423e19 PE |
273 | |
274 | /* Map characters from one character set to another. | |
275 | C is the character to be translated. */ | |
276 | ||
277 | char | |
278 | mvs_map_char (c) | |
279 | char c; | |
280 | { | |
281 | #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC) | |
92d6db66 | 282 | fprintf (stderr, "mvs_map_char: TE & !HE: c = %02x\n", c); |
f2423e19 PE |
283 | return ascebc[c]; |
284 | #else | |
285 | #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC) | |
92d6db66 | 286 | fprintf (stderr, "mvs_map_char: !TE & HE: c = %02x\n", c); |
f2423e19 PE |
287 | return ebcasc[c]; |
288 | #else | |
92d6db66 | 289 | fprintf (stderr, "mvs_map_char: !TE & !HE: c = %02x\n", c); |
f2423e19 PE |
290 | return c; |
291 | #endif | |
292 | #endif | |
293 | } | |
294 | ||
92d6db66 LV |
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. | |
303 | */ | |
304 | ||
305 | /* Return the destination address of a branch. */ | |
306 | ||
307 | int | |
308 | i370_branch_dest (branch) | |
309 | rtx branch; | |
310 | { | |
311 | rtx dest = SET_SRC (PATTERN (branch)); | |
312 | int dest_uid; | |
313 | int dest_addr; | |
314 | ||
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]; | |
321 | ||
322 | /* next, record the address of this insn as the true addr of first ref */ | |
323 | { | |
324 | label_node_t *lp; | |
325 | rtx label = JUMP_LABEL (branch); | |
326 | int labelno = CODE_LABEL_NUMBER (label); | |
327 | ||
328 | if (!label || CODE_LABEL != GET_CODE (label)) abort (); | |
329 | ||
330 | lp = mvs_get_label (labelno); | |
331 | if (-1 == lp -> first_ref_page) lp->first_ref_page = mvs_page_num; | |
332 | } | |
333 | return dest_addr; | |
334 | } | |
335 | ||
336 | int | |
337 | i370_branch_length (insn) | |
338 | rtx insn; | |
339 | { | |
340 | int here, there; | |
341 | here = insn_addresses[INSN_UID (insn)]; | |
342 | there = i370_branch_dest (insn); | |
343 | return (there - here); | |
344 | } | |
345 | ||
346 | ||
347 | int | |
348 | i370_short_branch (insn) | |
349 | rtx insn; | |
350 | { | |
351 | int base_offset; | |
352 | ||
353 | base_offset = i370_branch_length(insn); | |
354 | if (0 > base_offset) | |
355 | { | |
356 | base_offset += mvs_page_code; | |
357 | } | |
358 | else | |
359 | { | |
360 | /* avoid bumping into lit pool; use 2x to estimate max possible lits */ | |
361 | base_offset *= 2; | |
362 | base_offset += mvs_page_code + mvs_page_lit; | |
363 | } | |
364 | ||
365 | /* make a conservative estimate of room left on page */ | |
366 | if ((4060 >base_offset) && ( 0 < base_offset)) return 1; | |
367 | return 0; | |
368 | } | |
369 | ||
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 | |
ff9350e7 | 373 | code page as the label. If they do, then we can avoid |
92d6db66 LV |
374 | a reload of the base register for that label. |
375 | ||
ff9350e7 | 376 | Note that the instruction addresses used here are only |
92d6db66 LV |
377 | approximate, and make the sizes of the jumps appear |
378 | farther apart then they will actually be. This makes | |
ff9350e7 | 379 | this code far more conservative than it needs to be. |
92d6db66 LV |
380 | */ |
381 | ||
382 | #define I370_RECORD_LABEL_REF(label,addr) { \ | |
383 | label_node_t *lp; \ | |
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; \ | |
388 | } | |
389 | ||
390 | void | |
391 | i370_label_scan (void) | |
392 | { | |
393 | rtx insn; | |
394 | label_node_t *lp; | |
395 | int tablejump_offset = 0; | |
396 | ||
397 | for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) | |
398 | { | |
399 | int here = insn_addresses[INSN_UID (insn)]; | |
400 | enum rtx_code code = GET_CODE(insn); | |
401 | ||
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; | |
406 | ||
407 | /* check to see if this insn is a label ... */ | |
408 | if (CODE_LABEL == code) | |
409 | { | |
410 | int labelno = CODE_LABEL_NUMBER (insn); | |
411 | ||
412 | lp = mvs_get_label (labelno); | |
413 | lp -> label_addr = here; | |
414 | #if 0 | |
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); | |
419 | rtx ref = labelref; | |
420 | do | |
421 | { | |
422 | rtx linsn = CONTAINING_INSN(ref); | |
423 | ref = LABEL_NEXTREF(ref); | |
424 | } while (ref && (ref != labelref)); | |
425 | #endif | |
426 | } | |
427 | else | |
428 | if (JUMP_INSN == code) | |
429 | { | |
430 | rtx label = JUMP_LABEL (insn); | |
431 | int labelno; | |
432 | ||
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. */ | |
436 | if (!label) | |
437 | { | |
438 | int j; | |
439 | rtx body = PATTERN (insn); | |
440 | if (ADDR_VEC == GET_CODE(body)) | |
441 | { | |
442 | for (j=0; j < XVECLEN (body, 0); j++) | |
443 | { | |
444 | int labelno; | |
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; | |
450 | here += 4; | |
451 | I370_RECORD_LABEL_REF(label,here); | |
452 | } | |
453 | /* finished with the vector go do next insn */ | |
454 | continue; | |
455 | } | |
456 | else | |
457 | if (ADDR_DIFF_VEC == GET_CODE(body)) | |
458 | { | |
459 | /* XXX hack alert. | |
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. | |
466 | ||
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. | |
471 | ||
472 | However, the current situation is not any worse than it was | |
ff9350e7 LV |
473 | last week, and so we punt for now. */ |
474 | ||
92d6db66 LV |
475 | debug_rtx (insn); |
476 | // abort(); | |
477 | for (j=0; j < XVECLEN (body, 0); j++) | |
478 | { | |
479 | int labelno; | |
480 | } | |
481 | /* finished with the vector go do next insn */ | |
482 | continue; | |
483 | } | |
484 | else | |
485 | { | |
ff9350e7 LV |
486 | /* XXX hack alert. |
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)))) | |
490 | {indirect_jump} | |
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. */ | |
496 | ||
497 | /* print_rtl_single (stdout, insn); */ | |
92d6db66 | 498 | debug_rtx (insn); |
ff9350e7 | 499 | /* abort(); */ |
92d6db66 LV |
500 | continue; |
501 | } | |
502 | } | |
ff9350e7 LV |
503 | else |
504 | { | |
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); | |
509 | } | |
92d6db66 LV |
510 | } |
511 | ||
512 | /* Sometimes, we take addresses of labels and use them | |
513 | as instruction operands ... these show up as REG_NOTES */ | |
514 | else | |
515 | if (INSN == code) | |
516 | { | |
517 | if ('i' == GET_RTX_CLASS (code)) | |
518 | { | |
519 | rtx note; | |
520 | for (note = REG_NOTES (insn); note; note = XEXP(note,1)) | |
521 | { | |
522 | if (REG_LABEL == REG_NOTE_KIND(note)) | |
523 | { | |
524 | rtx label = XEXP (note,0); | |
525 | if (!label || CODE_LABEL != GET_CODE (label)) abort (); | |
526 | ||
527 | I370_RECORD_LABEL_REF(label,here); | |
528 | } | |
529 | } | |
530 | } | |
531 | } | |
532 | } | |
533 | } | |
534 | ||
535 | /* ===================================================== */ | |
536 | ||
f2423e19 PE |
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 | |
92d6db66 LV |
539 | in the code. |
540 | ||
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 | |
547 | L r4,=A(.LPGT0) | |
548 | ||
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 ... | |
552 | */ | |
f2423e19 PE |
553 | |
554 | int | |
555 | check_label_emit (void) | |
556 | { | |
92d6db66 | 557 | if (mvs_need_base_reload) |
f2423e19 | 558 | { |
92d6db66 LV |
559 | mvs_need_base_reload = 0; |
560 | ||
f2423e19 PE |
561 | mvs_page_code += 4; |
562 | fprintf (assembler_source, "\tL\t%d,%d(,%d)\n", | |
563 | BASE_REGISTER, (mvs_page_num - function_base_page) * 4, | |
564 | PAGE_REGISTER); | |
565 | } | |
566 | } | |
567 | ||
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. */ | |
572 | ||
92d6db66 LV |
573 | label_node_t * |
574 | mvs_get_label (id) | |
f2423e19 PE |
575 | int id; |
576 | { | |
577 | label_node_t *lp; | |
578 | ||
92d6db66 LV |
579 | /* first, lets see if we already go one, if so, use that. */ |
580 | for (lp = label_anchor; lp; lp = lp->label_next) | |
581 | { | |
582 | if (lp->label_id == id) return lp; | |
583 | } | |
584 | ||
585 | /* not found, get a new one */ | |
f2423e19 PE |
586 | if (free_anchor) |
587 | { | |
588 | lp = free_anchor; | |
589 | free_anchor = lp->label_next; | |
590 | } | |
591 | else | |
592 | { | |
92d6db66 | 593 | lp = (label_node_t *) xmalloc (sizeof (label_node_t)); |
f2423e19 | 594 | } |
92d6db66 LV |
595 | |
596 | /* initialize for new label */ | |
f2423e19 | 597 | lp->label_id = id; |
92d6db66 | 598 | lp->label_page = -1; |
f2423e19 | 599 | lp->label_next = label_anchor; |
92d6db66 LV |
600 | lp->label_first_ref = 2000123123; |
601 | lp->label_last_ref = -1; | |
602 | lp->label_addr = -1; | |
603 | lp->first_ref_page = -1; | |
f2423e19 | 604 | label_anchor = lp; |
92d6db66 LV |
605 | |
606 | return lp; | |
f2423e19 PE |
607 | } |
608 | ||
92d6db66 LV |
609 | void |
610 | mvs_add_label (id) | |
611 | int id; | |
612 | { | |
613 | label_node_t *lp; | |
614 | int fwd_distance; | |
615 | ||
616 | lp = mvs_get_label (id); | |
617 | lp->label_page = mvs_page_num; | |
618 | ||
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)) | |
623 | { | |
624 | /* Yep; the first label_ref was on a different page. */ | |
625 | mvs_need_base_reload ++; | |
626 | return; | |
627 | } | |
628 | ||
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. | |
636 | ||
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. */ | |
640 | ||
641 | /* if latest ref comes before label, we are clear */ | |
642 | if (lp->label_last_ref < lp->label_addr) return; | |
643 | ||
644 | fwd_distance = lp->label_last_ref - lp->label_addr; | |
645 | ||
646 | if (mvs_page_code + 2*fwd_distance + mvs_page_lit < 4060) return; | |
647 | ||
648 | mvs_need_base_reload ++; | |
649 | } | |
650 | ||
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. | |
f2423e19 PE |
657 | ID is the label number of the label being checked. */ |
658 | ||
659 | int | |
660 | mvs_check_label (id) | |
661 | int id; | |
662 | { | |
663 | label_node_t *lp; | |
664 | ||
665 | for (lp = label_anchor; lp; lp = lp->label_next) | |
666 | { | |
92d6db66 LV |
667 | if (lp->label_id == id) |
668 | { | |
669 | if (lp->label_page == mvs_page_num) | |
670 | { | |
671 | return 1; | |
672 | } | |
673 | else | |
674 | { | |
675 | return 0; | |
676 | } | |
677 | } | |
f2423e19 PE |
678 | } |
679 | return 0; | |
680 | } | |
681 | ||
92d6db66 LV |
682 | /* Get the page on which the label sits. This will be used to |
683 | determine is a register reload is really needed. */ | |
684 | ||
685 | int | |
686 | mvs_get_label_page(int id) | |
687 | { | |
688 | label_node_t *lp; | |
689 | ||
690 | for (lp = label_anchor; lp; lp = lp->label_next) | |
691 | { | |
692 | if (lp->label_id == id) | |
693 | return lp->label_page; | |
694 | } | |
695 | return -1; | |
696 | } | |
697 | ||
f2423e19 PE |
698 | /* The label list for the current page freed by linking the list onto the free |
699 | label element chain. */ | |
700 | ||
92d6db66 LV |
701 | void |
702 | mvs_free_label_list (void) | |
f2423e19 | 703 | { |
92d6db66 | 704 | |
f2423e19 PE |
705 | if (label_anchor) |
706 | { | |
92d6db66 LV |
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; | |
f2423e19 PE |
710 | free_anchor = label_anchor; |
711 | } | |
712 | label_anchor = 0; | |
713 | } | |
714 | ||
92d6db66 | 715 | /* ====================================================================== */ |
f2423e19 PE |
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. */ | |
723 | ||
92d6db66 | 724 | #ifdef TARGET_HLASM |
f2423e19 PE |
725 | int |
726 | mvs_check_page (file, code, lit) | |
727 | FILE *file; | |
728 | int code, lit; | |
729 | { | |
730 | if (file) | |
731 | assembler_source = file; | |
732 | ||
733 | if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH) | |
734 | { | |
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); | |
741 | mvs_page_num++; | |
92d6db66 LV |
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); | |
f2423e19 PE |
745 | fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num); |
746 | fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER); | |
f2423e19 PE |
747 | mvs_page_code = code; |
748 | mvs_page_lit = lit; | |
749 | return 1; | |
750 | } | |
751 | mvs_page_code += code; | |
752 | mvs_page_lit += lit; | |
753 | return 0; | |
754 | } | |
92d6db66 LV |
755 | #endif /* TARGET_HLASM */ |
756 | ||
757 | ||
758 | #ifdef TARGET_ELF_ABI | |
759 | int | |
760 | mvs_check_page (file, code, lit) | |
761 | FILE *file; | |
762 | int code, lit; | |
763 | { | |
764 | if (file) | |
765 | assembler_source = file; | |
766 | ||
767 | if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH) | |
768 | { | |
769 | /* hop past the literal pool */ | |
770 | fprintf (assembler_source, "\tB\t.LPGE%d\n", mvs_page_num); | |
771 | ||
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"); | |
778 | ||
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); | |
782 | mvs_page_num++; | |
783 | ||
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; | |
790 | mvs_page_lit = lit; | |
791 | return 1; | |
792 | } | |
793 | mvs_page_code += code; | |
794 | mvs_page_lit += lit; | |
795 | return 0; | |
796 | } | |
797 | #endif /* TARGET_ELF_ABI */ | |
798 | ||
799 | /* ===================================================== */ | |
800 | /* defines and functions specific to the HLASM assembler */ | |
801 | #ifdef TARGET_HLASM | |
f2423e19 PE |
802 | |
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. */ | |
806 | ||
807 | int | |
808 | mvs_function_check (name) | |
809 | char *name; | |
810 | { | |
811 | int lower, middle, upper; | |
812 | int i; | |
813 | ||
814 | lower = 0; | |
815 | upper = MVS_FUNCTION_TABLE_LENGTH - 1; | |
816 | while (lower <= upper) | |
817 | { | |
818 | middle = (lower + upper) / 2; | |
819 | i = strcmp (name, mvs_function_table[middle]); | |
820 | if (i == 0) | |
821 | return 1; | |
822 | if (i < 0) | |
823 | upper = middle - 1; | |
824 | else | |
825 | lower = middle + 1; | |
826 | } | |
827 | return 0; | |
828 | } | |
829 | ||
830 | ||
92d6db66 LV |
831 | /* Add the alias to the current alias list. */ |
832 | ||
833 | int | |
834 | mvs_add_alias (realname, aliasname, emitted) | |
835 | char *realname; | |
836 | char *aliasname; | |
837 | int emitted; | |
838 | { | |
839 | alias_node_t *ap; | |
840 | ||
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; | |
846 | alias_anchor = ap; | |
847 | } | |
848 | ||
849 | /* Check to see if the name needs aliasing */ | |
850 | ||
851 | int | |
852 | mvs_need_alias (realname) | |
853 | char *realname; | |
854 | { | |
855 | if (mvs_function_check (realname)) | |
856 | return 0; | |
857 | if (strlen (realname) > MAX_MVS_LABEL_SIZE) | |
858 | return 1; | |
859 | if (strchr (realname, '_') != 0) | |
860 | return 1; | |
861 | return 0; | |
862 | } | |
863 | ||
864 | /* Get the alias from the list. | |
865 | If 1 is returned then it's in the alias list, 0 if it was not */ | |
866 | ||
867 | int | |
868 | mvs_get_alias (realname, aliasname) | |
869 | char *realname; | |
870 | char *aliasname; | |
871 | { | |
872 | #ifdef LONGEXTERNAL | |
873 | alias_node_t *ap; | |
874 | ||
875 | for (ap = alias_anchor; ap; ap = ap->alias_next) | |
876 | { | |
877 | if (!strcmp (ap->real_name, realname)) | |
878 | { | |
879 | strcpy (aliasname, ap->alias_name); | |
880 | return 1; | |
881 | } | |
882 | } | |
883 | if (mvs_need_alias (realname)) | |
884 | { | |
885 | sprintf (aliasname, "ALS%05d", alias_number++); | |
886 | mvs_add_alias (realname, aliasname, 0); | |
887 | return 1; | |
888 | } | |
889 | #else | |
890 | if (strlen (realname) > MAX_MVS_LABEL_SIZE) | |
891 | { | |
892 | strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE); | |
893 | aliasname[MAX_MVS_LABEL_SIZE] = '\0'; | |
894 | return 1; | |
895 | } | |
896 | #endif | |
897 | return 0; | |
898 | } | |
899 | ||
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 */ | |
902 | ||
903 | int | |
904 | mvs_check_alias (realname, aliasname) | |
905 | char *realname; | |
906 | char *aliasname; | |
907 | { | |
908 | #ifdef LONGEXTERNAL | |
909 | alias_node_t *ap; | |
910 | ||
911 | for (ap = alias_anchor; ap; ap = ap->alias_next) | |
912 | { | |
913 | if (!strcmp (ap->real_name, realname)) | |
914 | { | |
915 | int rc = (ap->alias_emitted == 1) ? 1 : 2; | |
916 | strcpy (aliasname, ap->alias_name); | |
917 | ap->alias_emitted = 1; | |
918 | return rc; | |
919 | } | |
920 | } | |
921 | if (mvs_need_alias (realname)) | |
922 | { | |
923 | sprintf (aliasname, "ALS%05d", alias_number++); | |
924 | mvs_add_alias (realname, aliasname, 0); | |
925 | alias_anchor->alias_emitted = 1; | |
926 | return 2; | |
927 | } | |
928 | #else | |
929 | if (strlen (realname) > MAX_MVS_LABEL_SIZE) | |
930 | { | |
931 | strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE); | |
932 | aliasname[MAX_MVS_LABEL_SIZE] = '\0'; | |
933 | return 1; | |
934 | } | |
935 | #endif | |
936 | return 0; | |
937 | } | |
938 | ||
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. */ | |
943 | ||
944 | int | |
945 | handle_pragma (finput, node) | |
946 | FILE *finput; | |
947 | tree node; | |
948 | { | |
949 | int retval = 0; | |
950 | register int c; | |
951 | register char *pname; | |
952 | ||
953 | if (TREE_CODE (node) != IDENTIFIER_NODE) | |
954 | return 0; | |
955 | ||
956 | pname = IDENTIFIER_POINTER (node); | |
957 | ||
958 | if (strcmp (pname, "map") == 0) | |
959 | { | |
960 | char realname[MAX_LONG_LABEL_SIZE + 1]; | |
961 | char aliasname[MAX_MVS_LABEL_SIZE + 1]; | |
962 | char *s; | |
963 | ||
964 | do { | |
965 | c = getc (finput); | |
966 | } while (c == ' ' || c == '\t'); | |
967 | ||
968 | if (c == '(') | |
969 | { | |
970 | s = realname; | |
971 | do { | |
972 | c = getc (finput); | |
973 | } while (c == ' ' || c == '\t'); | |
974 | if (c == '\n') | |
975 | goto PRAGMA_WARNING; | |
976 | do { | |
977 | *s++ = c; | |
978 | c = getc (finput); | |
92a438d1 | 979 | } while (ISALNUM(c) || c == '_'); |
92d6db66 LV |
980 | if (c == '\n') |
981 | goto PRAGMA_WARNING; | |
982 | *s = 0; | |
983 | ||
984 | if (c == ' ' || c == '\t') | |
985 | do { | |
986 | c = getc (finput); | |
987 | } while (c == ' ' || c == '\t'); | |
988 | ||
989 | if (c == ',') | |
990 | { | |
991 | do { | |
992 | c = getc (finput); | |
993 | } while (c == ' ' || c == '\t'); | |
994 | if (c == '"') | |
995 | { | |
996 | s = aliasname; | |
997 | c = getc(finput); | |
998 | do { | |
999 | if (c == '\\') | |
1000 | { | |
1001 | int d = 0; | |
1002 | do { | |
1003 | c = getc(finput); | |
1004 | if (c >= '0' && c <= '7') | |
1005 | d = (d << 3) | c - '0'; | |
1006 | } while (c >= '0' && c <= '7'); | |
1007 | ungetc (c, finput); | |
1008 | c = d; | |
1009 | if (d < 1 || d > 255) | |
1010 | warning ("Escape value out of range"); | |
1011 | #ifndef HOST_EBCDIC | |
1012 | c = ebcasc[c]; | |
1013 | #endif | |
1014 | } | |
1015 | *s++ = c; | |
1016 | c = getc (finput); | |
92a438d1 | 1017 | if (ISSPACE(c) || c == ')') |
92d6db66 LV |
1018 | goto PRAGMA_WARNING; |
1019 | } while (c != '"'); | |
1020 | *s = 0; | |
1021 | if (strlen (aliasname) > MAX_MVS_LABEL_SIZE) | |
1022 | { | |
1023 | warning ("#pragma map alias is too long, truncated"); | |
1024 | aliasname[MAX_MVS_LABEL_SIZE] = '\0'; | |
1025 | } | |
1026 | do { | |
1027 | c = getc (finput); | |
1028 | } while (c == ' ' || c == '\t'); | |
1029 | if (c == ')') | |
1030 | { | |
1031 | mvs_add_alias (realname, aliasname, 1); | |
1032 | retval = 1; | |
1033 | } | |
1034 | else | |
1035 | goto PRAGMA_WARNING; | |
1036 | } | |
1037 | else | |
1038 | goto PRAGMA_WARNING; | |
1039 | } | |
1040 | else | |
1041 | goto PRAGMA_WARNING; | |
1042 | ||
1043 | } | |
1044 | else | |
1045 | { | |
1046 | PRAGMA_WARNING: | |
1047 | warning ("#pragma map options are missing or incorrect"); | |
1048 | } | |
1049 | ||
1050 | } | |
1051 | ||
1052 | return retval; | |
1053 | } | |
1054 | ||
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 | |
1061 | ||
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 ??) */ | |
1066 | ||
1067 | int | |
1068 | mvs_function_check (name) | |
1069 | char *name; | |
1070 | { | |
1071 | return 0; | |
1072 | } | |
1073 | ||
1074 | #endif /* TARGET_ELF_ABI */ | |
1075 | /* ===================================================== */ | |
1076 | ||
1077 | ||
f2423e19 PE |
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. */ | |
1081 | ||
1082 | int | |
1083 | s_operand (op, mode) | |
1084 | register rtx op; | |
1085 | enum machine_mode mode; | |
1086 | { | |
1087 | extern int volatile_ok; | |
1088 | register enum rtx_code code = GET_CODE (op); | |
1089 | ||
1090 | if (CONSTANT_ADDRESS_P (op)) | |
1091 | return 1; | |
1092 | if (mode == VOIDmode || GET_MODE (op) != mode) | |
1093 | return 0; | |
1094 | if (code == MEM) | |
1095 | { | |
1096 | register rtx x = XEXP (op, 0); | |
1097 | ||
1098 | if (!volatile_ok && op->volatil) | |
1099 | return 0; | |
1100 | if (REG_P (x) && REG_OK_FOR_BASE_P (x)) | |
1101 | return 1; | |
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) | |
1106 | return 1; | |
1107 | } | |
1108 | return 0; | |
1109 | } | |
1110 | ||
1111 | ||
1112 | /* Return 1 if OP is a valid R or S operand for an RS, SI or SS type | |
1113 | instruction. | |
1114 | OP is the current operation. | |
1115 | MODE is the current operation mode. */ | |
1116 | ||
1117 | int | |
1118 | r_or_s_operand (op, mode) | |
1119 | register rtx op; | |
1120 | enum machine_mode mode; | |
1121 | { | |
1122 | extern int volatile_ok; | |
1123 | register enum rtx_code code = GET_CODE (op); | |
1124 | ||
1125 | if (CONSTANT_ADDRESS_P (op)) | |
1126 | return 1; | |
1127 | if (mode == VOIDmode || GET_MODE (op) != mode) | |
1128 | return 0; | |
1129 | if (code == REG) | |
1130 | return 1; | |
1131 | else if (code == MEM) | |
1132 | { | |
1133 | register rtx x = XEXP (op, 0); | |
1134 | ||
1135 | if (!volatile_ok && op->volatil) | |
1136 | return 0; | |
1137 | if (REG_P (x) && REG_OK_FOR_BASE_P (x)) | |
1138 | return 1; | |
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) | |
1143 | return 1; | |
1144 | } | |
1145 | return 0; | |
1146 | } | |
1147 | ||
1148 | ||
92d6db66 LV |
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. | |
1159 | ||
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. | |
1164 | ||
1165 | The unsigned_jump_follows_p() routine returns a 1 if the next jump | |
1166 | is unsigned. INSN is the current instruction. */ | |
f2423e19 PE |
1167 | |
1168 | unsigned_jump_follows_p (insn) | |
1169 | register rtx insn; | |
1170 | { | |
92d6db66 LV |
1171 | rtx orig_insn = insn; |
1172 | while (1) | |
1173 | { | |
1174 | register rtx tmp_insn; | |
1175 | enum rtx_code coda; | |
1176 | ||
1177 | insn = NEXT_INSN (insn); | |
1178 | if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn); | |
1179 | ||
1180 | if (GET_CODE (insn) != JUMP_INSN) continue; | |
1181 | ||
1182 | tmp_insn = XEXP (insn, 3); | |
1183 | if (GET_CODE (tmp_insn) != SET) continue; | |
1184 | ||
1185 | if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue; | |
1186 | ||
1187 | tmp_insn = XEXP (tmp_insn, 1); | |
1188 | if (GET_CODE (tmp_insn) != IF_THEN_ELSE) continue; | |
1189 | ||
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); | |
1193 | ||
1194 | return coda != GE && coda != GT && coda != LE && coda != LT; | |
1195 | } | |
1196 | } | |
f2423e19 | 1197 | |
f2423e19 | 1198 | |
92d6db66 | 1199 | #ifdef TARGET_HLASM |
a0d66c8d JL |
1200 | |
1201 | void | |
1202 | i370_function_prolog (f, l) | |
1203 | FILE *f; | |
1204 | int l; | |
1205 | { | |
1206 | #if MACROPROLOGUE == 1 | |
92d6db66 | 1207 | fprintf (f, "* Function %s prologue\n", mvs_function_name); |
a0d66c8d JL |
1208 | fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n", |
1209 | STACK_POINTER_OFFSET + l - 120 + | |
1210 | current_function_outgoing_args_size, BASE_REGISTER); | |
a0d66c8d JL |
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; | |
1216 | int i; | |
92d6db66 LV |
1217 | #if defined(LE370) |
1218 | if (!function_first) | |
1219 | { | |
1220 | struct tm *function_time; | |
1221 | time_t lcltime; | |
1222 | time (&lcltime); | |
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; | |
1230 | } | |
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), | |
1254 | 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); | |
1283 | function_first = 1; | |
1284 | function_label_index ++; | |
1285 | #else /* !LE370 */ | |
a0d66c8d JL |
1286 | if (!function_first) |
1287 | { | |
1288 | struct tm *function_time; | |
1289 | time_t lcltime; | |
1290 | time (&lcltime); | |
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"); | |
1307 | } | |
92d6db66 LV |
1308 | fprintf (f, "* Function %s prologue\n", mvs_function_name); |
1309 | fprintf (f, "FDSD%03d\tDSECT\n", function_label_index); | |
a0d66c8d JL |
1310 | fprintf (f, "\tDS\tD\n"); |
1311 | fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l | |
1312 | + current_function_outgoing_args_size); | |
92d6db66 | 1313 | fprintf (f, "\tORG\tFDSD%03d\n", function_label_index); |
a0d66c8d JL |
1314 | fprintf (f, "\tDS\tCL(120+8)\n"); |
1315 | fprintf (f, "\tORG\n"); | |
1316 | fprintf (f, "\tDS\t0D\n"); | |
92d6db66 | 1317 | fprintf (f, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index, |
a0d66c8d JL |
1318 | function_label_index); |
1319 | fprintf (f, "\tDS\t0H\n"); | |
1320 | assemble_name (f, mvs_function_name); | |
92d6db66 | 1321 | fprintf (f, "\tCSECT\n"); |
a0d66c8d JL |
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"); | |
92d6db66 | 1328 | fprintf (f, "\tDC\tAL4(FDSL%03d)\n", function_label_index); |
a0d66c8d JL |
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), | |
1331 | 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); | |
a0d66c8d | 1349 | fprintf (f, "\tUSING\t*,%d\n", BASE_REGISTER); |
92d6db66 LV |
1350 | function_first = 1; |
1351 | function_label_index += 2; | |
1352 | #endif /* !LE370 */ | |
1353 | #endif /* MACROPROLOGUE */ | |
1354 | fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num ); | |
1355 | fprintf (f, "\tLR\t11,1\n"); | |
a0d66c8d | 1356 | fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num); |
92d6db66 LV |
1357 | fprintf (f, "* Function %s code\n", mvs_function_name); |
1358 | ||
1359 | mvs_free_label_list (); | |
1360 | mvs_page_code = 6; | |
a0d66c8d JL |
1361 | mvs_page_lit = 4; |
1362 | mvs_check_page (f, 0, 0); | |
1363 | function_base_page = mvs_page_num; | |
92d6db66 LV |
1364 | |
1365 | /* find all labels in this routine */ | |
1366 | i370_label_scan (); | |
1367 | } | |
1368 | #endif /* TARGET_HLASM */ | |
1369 | ||
1370 | ||
1371 | #ifdef TARGET_ELF_ABI | |
1372 | /* | |
1373 | The 370_function_prolog() routine generates the current ELF ABI ES/390 prolog. | |
ff9350e7 | 1374 | It implements a stack that grows downward. |
92d6db66 LV |
1375 | It performs the following steps: |
1376 | -- saves the callers non-volatile registers on the callers stack. | |
ff9350e7 LV |
1377 | -- subtracts stackframe size from the stack pointer. |
1378 | -- stores backpointer to old caller stack. | |
92d6db66 LV |
1379 | |
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. | |
1384 | ||
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. | |
1390 | */ | |
1391 | ||
1392 | void | |
1393 | i370_function_prolog (f, frame_size) | |
1394 | FILE *f; | |
1395 | int frame_size; | |
1396 | { | |
1397 | static int function_label_index = 1; | |
1398 | static int function_first = 0; | |
1399 | int i; | |
1400 | int stackframe_size, soffset, aligned_size; | |
1401 | ||
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 */ | |
1406 | stackframe_size = | |
1407 | STACK_POINTER_OFFSET + current_function_outgoing_args_size + frame_size; | |
1408 | aligned_size = (stackframe_size + 7) >> 3; | |
1409 | aligned_size <<= 3; | |
1410 | ||
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); | |
1413 | ||
1414 | fprintf (f, "\t.using\t.,r15\n"); | |
1415 | ||
1416 | /* Branch to exectuable part of prologue. */ | |
1417 | fprintf (f, "\tB\t.LFENT%03d\n", function_label_index); | |
1418 | ||
1419 | /* write the length of the stackframe */ | |
1420 | fprintf (f, "\t.long\t%d\n", aligned_size); | |
1421 | ||
1422 | /* FENT == function prologue entry */ | |
ff9350e7 | 1423 | fprintf (f, "\t.balign 2\n.LFENT%03d:\n", |
92d6db66 LV |
1424 | function_label_index); |
1425 | ||
ff9350e7 | 1426 | /* store multiple registers 14,15,0,...12 at 12 bytes from sp */ |
92d6db66 LV |
1427 | fprintf (f, "\tSTM\tr14,r12,12(sp)\n"); |
1428 | ||
ff9350e7 LV |
1429 | /* r3 == saved callee stack pointer */ |
1430 | fprintf (f, "\tLR\tr3,sp\n"); | |
92d6db66 | 1431 | |
ff9350e7 LV |
1432 | /* 4(r15) == stackframe size */ |
1433 | fprintf (f, "\tSL\tsp,4(,r15)\n"); | |
92d6db66 | 1434 | |
ff9350e7 LV |
1435 | /* r11 points to arg list in callers stackframe; was passed in r2 */ |
1436 | fprintf (f, "\tLR\tr11,r2\n"); | |
92d6db66 LV |
1437 | |
1438 | /* store callee stack pointer at 8(sp) */ | |
ff9350e7 | 1439 | /* fprintf (f, "\tST\tsp,8(,r3)\n "); wasted cycles, no one uses this ... */ |
92d6db66 | 1440 | |
ff9350e7 LV |
1441 | /* backchain -- store caller sp at 4(callee_sp) */ |
1442 | fprintf (f, "\tST\tr3,4(,sp)\n "); | |
92d6db66 LV |
1443 | |
1444 | fprintf (f, "\t.drop\tr15\n"); | |
ff9350e7 LV |
1445 | /* Place contents of the PSW into r3 |
1446 | that is, place the address of "." into r3 */ | |
92d6db66 LV |
1447 | fprintf (f, "\tBASR\tr%d,0\n", BASE_REGISTER); |
1448 | fprintf (f, "\t.using\t.,r%d\n", BASE_REGISTER); | |
a0d66c8d | 1449 | function_first = 1; |
92d6db66 LV |
1450 | function_label_index ++; |
1451 | ||
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"); | |
1455 | ||
1456 | mvs_free_label_list (); | |
1457 | mvs_page_code = 6; | |
1458 | mvs_page_lit = 4; | |
1459 | mvs_check_page (f, 0, 0); | |
1460 | function_base_page = mvs_page_num; | |
1461 | ||
1462 | /* find all labels in this routine */ | |
1463 | i370_label_scan (); | |
a0d66c8d | 1464 | } |
92d6db66 | 1465 | #endif /* TARGET_ELF_ABI */ |