|
|
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.