|
|
1.1 root 1: /* Subroutines for insn-output.c for System/370.
2: Copyright (C) 1989, 1993 Free Software Foundation, Inc.
3: Contributed by Jan Stein ([email protected]).
4: Modified for MVS C/370 by Dave Pitts ([email protected])
5:
6: This file is part of GNU CC.
7:
8: GNU CC is free software; you can redistribute it and/or modify
9: it under the terms of the GNU General Public License as published by
10: the Free Software Foundation; either version 2, or (at your option)
11: any later version.
12:
13: GNU CC is distributed in the hope that it will be useful,
14: but WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: GNU General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with GNU CC; see the file COPYING. If not, write to
20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21:
22: #include <stdio.h>
23: #include <string.h>
24: #include <ctype.h>
25: #include "config.h"
26: #include "rtl.h"
27: #include "regs.h"
28: #include "hard-reg-set.h"
29: #include "real.h"
30: #include "insn-config.h"
31: #include "conditions.h"
32: #include "insn-flags.h"
33: #include "output.h"
34: #include "insn-attr.h"
35: #include "flags.h"
36: #include "recog.h"
37:
38:
39: /* Label node, this structure is used to keep track of labels on the
40: current page. */
41: typedef struct label_node
42: {
43: struct label_node *label_next;
44: int label_id;
45: int label_page;
46: }
47: label_node_t;
48:
49: /* Is 1 when a label has been generated and the base register must be
50: reloaded. */
51: int mvs_label_emited = 0;
52:
53: /* Current function starting base page. */
54: int function_base_page;
55:
56: /* Length of the current page code. */
57: int mvs_page_code;
58:
59: /* Length of the current page literals. */
60: int mvs_page_lit;
61:
62: /* Current function name. */
63: char *mvs_function_name = 0;
64:
65: /* Current function name length. */
66: int mvs_function_name_length = 0;
67:
68: /* Page number for multi-page functions. */
69: int mvs_page_num = 0;
70:
71: /* Label node list anchor. */
72: static label_node_t *label_anchor = 0;
73:
74: /* Label node free list anchor. */
75: static label_node_t *free_anchor = 0;
76:
77: /* Assembler source file decriptor. */
78: static FILE *assembler_source = 0;
79:
80: /* Define the length of the internal MVS function table. */
81: #define MVS_FUNCTION_TABLE_LENGTH 32
82:
83: /* C/370 internal function table. These functions use non-standard linkage
84: and must handled in a special manner. */
85: static char *mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] =
86: {
87: "ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
88: "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
89: "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
90: "fabs", "floor", "fmod", "frexp", "hypot", "j0",
91: "j1", "jn", "ldexp", "modf", "pow", "y0",
92: "y1", "yn"
93: };
94:
95: /* ASCII to EBCDIC conversion table. */
96: #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
97: static unsigned char ascebc[256] =
98: {
99: /*00 NL SH SX EX ET NQ AK BL */
100: 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
101: /*08 BS HT LF VT FF CR SO SI */
102: 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
103: /*10 DL D1 D2 D3 D4 NK SN EB */
104: 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
105: /*18 CN EM SB EC FS GS RS US */
106: 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
107: /*20 SP ! " # $ % & ' */
108: 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
109: /*28 ( ) * + , - . / */
110: 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
111: /*30 0 1 2 3 4 5 6 7 */
112: 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
113: /*38 8 9 : ; < = > ? */
114: 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
115: /*40 @ A B C D E F G */
116: 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
117: /*48 H I J K L M N O */
118: 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
119: /*50 P Q R S T U V W */
120: 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
121: /*58 X Y Z [ \ ] ^ _ */
122: 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
123: /*60 ` a b c d e f g */
124: 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
125: /*68 h i j k l m n o */
126: 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
127: /*70 p q r s t u v w */
128: 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
129: /*78 x y z { | } ~ DL */
130: 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
131: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
132: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
133: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
134: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
135: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
136: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
137: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
138: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
139: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
140: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
141: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
142: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
143: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
144: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
145: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
146: 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
147: };
148: #endif
149:
150: /* EBCDIC to ASCII conversion table. */
151: #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
152: unsigned char ebcasc[256] =
153: {
154: /*00 NU SH SX EX PF HT LC DL */
155: 0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F,
156: /*08 SM VT FF CR SO SI */
157: 0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
158: /*10 DE D1 D2 TM RS NL BS IL */
159: 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x08, 0x00,
160: /*18 CN EM CC C1 FS GS RS US */
161: 0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
162: /*20 DS SS FS BP LF EB EC */
163: 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
164: /*28 SM C2 EQ AK BL */
165: 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x00,
166: /*30 SY PN RS UC ET */
167: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
168: /*38 C3 D4 NK SU */
169: 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
170: /*40 SP */
171: 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172: /*48 . < ( + | */
173: 0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
174: /*50 & */
175: 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176: /*58 ! $ * ) ; ^ */
177: 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
178: /*60 - / */
179: 0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180: /*68 , % _ > ? */
181: 0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
182: /*70 */
183: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184: /*78 ` : # @ ' = " */
185: 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
186: /*80 a b c d e f g */
187: 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
188: /*88 h i { */
189: 0x68, 0x69, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00,
190: /*90 j k l m n o p */
191: 0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
192: /*98 q r } */
193: 0x71, 0x72, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,
194: /*A0 ~ s t u v w x */
195: 0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
196: /*A8 y z [ */
197: 0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
198: /*B0 */
199: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200: /*B8 ] */
201: 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
202: /*C0 { A B C D E F G */
203: 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
204: /*C8 H I */
205: 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206: /*D0 } J K L M N O P */
207: 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
208: /*D8 Q R */
209: 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210: /*E0 \ S T U V W X */
211: 0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
212: /*E8 Y Z */
213: 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214: /*F0 0 1 2 3 4 5 6 7 */
215: 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
216: /*F8 8 9 */
217: 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
218: };
219: #endif
220:
221: /* Map characters from one character set to another.
222: C is the character to be translated. */
223:
224: char
225: mvs_map_char (c)
226: char c;
227: {
228: #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
229: return ascebc[c];
230: #else
231: #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
232: return ebcasc[c];
233: #else
234: return c;
235: #endif
236: #endif
237: }
238:
239: /* Emit reload of base register if indicated. This is to eliminate multiple
240: reloads when several labels are generated pointing to the same place
241: in the code. */
242:
243: int
244: check_label_emit (void)
245: {
246: if (mvs_label_emited)
247: {
248: mvs_label_emited = 0;
249: mvs_page_code += 4;
250: fprintf (assembler_source, "\tL\t%d,%d(,%d)\n",
251: BASE_REGISTER, (mvs_page_num - function_base_page) * 4,
252: PAGE_REGISTER);
253: }
254: }
255:
256: /* Add the label to the current page label list. If a free element is available
257: it will be used for the new label. Otherwise, a label element will be
258: allocated from memory.
259: ID is the label number of the label being added to the list. */
260:
261: int
262: mvs_add_label (id)
263: int id;
264: {
265: label_node_t *lp;
266:
267: if (free_anchor)
268: {
269: lp = free_anchor;
270: free_anchor = lp->label_next;
271: }
272: else
273: {
274: lp = (label_node_t *) malloc (sizeof (label_node_t));
275: if (lp == 0)
276: {
277: fatal ("virtual memory exhausted\n");
278: abort ();
279: }
280: }
281: lp->label_id = id;
282: lp->label_page = mvs_page_num;
283: lp->label_next = label_anchor;
284: label_anchor = lp;
285: }
286:
287: /* Check to see if the label is in the list. If 1 is returned then a load
288: and branch on register must be generated.
289: ID is the label number of the label being checked. */
290:
291: int
292: mvs_check_label (id)
293: int id;
294: {
295: label_node_t *lp;
296:
297: for (lp = label_anchor; lp; lp = lp->label_next)
298: {
299: if (lp->label_id == id)
300: return 1;
301: }
302: return 0;
303: }
304:
305: /* The label list for the current page freed by linking the list onto the free
306: label element chain. */
307:
308: int
309: mvs_free_label (void)
310: {
311: if (label_anchor)
312: {
313: if (free_anchor)
314: label_anchor->label_next = free_anchor;
315: free_anchor = label_anchor;
316: }
317: label_anchor = 0;
318: }
319:
320: /* If the page size limit is reached a new code page is started, and the base
321: register is set to it. This page break point is counted conservatively,
322: most literals that have the same value are collapsed by the assembler.
323: True is returned when a new page is started.
324: FILE is the assembler output file descriptor.
325: CODE is the length, in bytes, of the instruction to be emitted.
326: LIT is the length of the literal to be emitted. */
327:
328: int
329: mvs_check_page (file, code, lit)
330: FILE *file;
331: int code, lit;
332: {
333: if (file)
334: assembler_source = file;
335:
336: if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH)
337: {
338: fprintf (assembler_source, "\tB\tPGE%d\n", mvs_page_num);
339: fprintf (assembler_source, "\tDS\t0F\n");
340: fprintf (assembler_source, "\tLTORG\n");
341: fprintf (assembler_source, "\tDS\t0F\n");
342: fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num);
343: fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER);
344: mvs_page_num++;
345: fprintf (assembler_source, "\tBALR\t%d,0\n", BASE_REGISTER);
346: fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num);
347: fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER);
348: mvs_free_label ();
349: mvs_page_code = code;
350: mvs_page_lit = lit;
351: return 1;
352: }
353: mvs_page_code += code;
354: mvs_page_lit += lit;
355: return 0;
356: }
357:
358: /* Check for C/370 runtime function, they don't use standard calling
359: conventions. True is returned if the function is in the table.
360: NAME is the name of the current function. */
361:
362: int
363: mvs_function_check (name)
364: char *name;
365: {
366: int lower, middle, upper;
367: int i;
368:
369: lower = 0;
370: upper = MVS_FUNCTION_TABLE_LENGTH - 1;
371: while (lower <= upper)
372: {
373: middle = (lower + upper) / 2;
374: i = strcmp (name, mvs_function_table[middle]);
375: if (i == 0)
376: return 1;
377: if (i < 0)
378: upper = middle - 1;
379: else
380: lower = middle + 1;
381: }
382: return 0;
383: }
384:
385:
386: /* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
387: OP is the current operation.
388: MODE is the current operation mode. */
389:
390: int
391: s_operand (op, mode)
392: register rtx op;
393: enum machine_mode mode;
394: {
395: extern int volatile_ok;
396: register enum rtx_code code = GET_CODE (op);
397:
398: if (CONSTANT_ADDRESS_P (op))
399: return 1;
400: if (mode == VOIDmode || GET_MODE (op) != mode)
401: return 0;
402: if (code == MEM)
403: {
404: register rtx x = XEXP (op, 0);
405:
406: if (!volatile_ok && op->volatil)
407: return 0;
408: if (REG_P (x) && REG_OK_FOR_BASE_P (x))
409: return 1;
410: if (GET_CODE (x) == PLUS
411: && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
412: && GET_CODE (XEXP (x, 1)) == CONST_INT
413: && (unsigned) INTVAL (XEXP (x, 1)) < 4096)
414: return 1;
415: }
416: return 0;
417: }
418:
419:
420: /* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
421: instruction.
422: OP is the current operation.
423: MODE is the current operation mode. */
424:
425: int
426: r_or_s_operand (op, mode)
427: register rtx op;
428: enum machine_mode mode;
429: {
430: extern int volatile_ok;
431: register enum rtx_code code = GET_CODE (op);
432:
433: if (CONSTANT_ADDRESS_P (op))
434: return 1;
435: if (mode == VOIDmode || GET_MODE (op) != mode)
436: return 0;
437: if (code == REG)
438: return 1;
439: else if (code == MEM)
440: {
441: register rtx x = XEXP (op, 0);
442:
443: if (!volatile_ok && op->volatil)
444: return 0;
445: if (REG_P (x) && REG_OK_FOR_BASE_P (x))
446: return 1;
447: if (GET_CODE (x) == PLUS
448: && REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
449: && GET_CODE (XEXP (x, 1)) == CONST_INT
450: && (unsigned) INTVAL (XEXP (x, 1)) < 4096)
451: return 1;
452: }
453: return 0;
454: }
455:
456:
457: /* Return 1 if the next instruction is an unsigned jump instruction.
458: INSN is the current instruction. */
459:
460: unsigned_jump_follows_p (insn)
461: register rtx insn;
462: {
463: insn = NEXT_INSN (insn);
464: if (GET_CODE (insn) != JUMP_INSN)
465: return 0;
466:
467: insn = XEXP (insn, 3);
468: if (GET_CODE (insn) != SET)
469: return 0;
470:
471: if (GET_CODE (XEXP (insn, 0)) != PC)
472: return 0;
473:
474: insn = XEXP (insn, 1);
475: if (GET_CODE (insn) != IF_THEN_ELSE)
476: return 0;
477:
478: insn = XEXP (insn, 0);
479: return GET_CODE (insn) != GE && GET_CODE (insn) != GT
480: && GET_CODE (insn) != LE && GET_CODE (insn) != LT;
481: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.