1998-03-29 12:14:27 +04:00
|
|
|
/* Subroutines for insn-output.c for System/370.
|
1998-08-16 21:35:45 +04:00
|
|
|
Copyright (C) 1989, 1993, 1995, 1997 Free Software Foundation, Inc.
|
1998-03-29 12:14:27 +04:00
|
|
|
Contributed by Jan Stein (jan@cd.chalmers.se).
|
|
|
|
Modified for MVS C/370 by Dave Pitts (dpitts@nyx.cs.du.edu)
|
|
|
|
|
|
|
|
This file is part of GNU CC.
|
|
|
|
|
|
|
|
GNU CC is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
GNU CC is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with GNU CC; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
|
1998-08-16 21:35:45 +04:00
|
|
|
#include "config.h"
|
1998-03-29 12:14:27 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "rtl.h"
|
|
|
|
#include "regs.h"
|
|
|
|
#include "hard-reg-set.h"
|
|
|
|
#include "real.h"
|
|
|
|
#include "insn-config.h"
|
|
|
|
#include "conditions.h"
|
|
|
|
#include "insn-flags.h"
|
|
|
|
#include "output.h"
|
|
|
|
#include "insn-attr.h"
|
|
|
|
#include "flags.h"
|
|
|
|
#include "recog.h"
|
1998-08-16 21:35:45 +04:00
|
|
|
#ifdef sun
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#endif
|
|
|
|
#include <time.h>
|
1998-03-29 12:14:27 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* Label node, this structure is used to keep track of labels on the
|
|
|
|
current page. */
|
|
|
|
typedef struct label_node
|
|
|
|
{
|
|
|
|
struct label_node *label_next;
|
|
|
|
int label_id;
|
|
|
|
int label_page;
|
|
|
|
}
|
|
|
|
label_node_t;
|
|
|
|
|
|
|
|
/* Is 1 when a label has been generated and the base register must be
|
|
|
|
reloaded. */
|
|
|
|
int mvs_label_emitted = 0;
|
|
|
|
|
|
|
|
/* Current function starting base page. */
|
|
|
|
int function_base_page;
|
|
|
|
|
|
|
|
/* Length of the current page code. */
|
|
|
|
int mvs_page_code;
|
|
|
|
|
|
|
|
/* Length of the current page literals. */
|
|
|
|
int mvs_page_lit;
|
|
|
|
|
|
|
|
/* Current function name. */
|
|
|
|
char *mvs_function_name = 0;
|
|
|
|
|
|
|
|
/* Current function name length. */
|
|
|
|
int mvs_function_name_length = 0;
|
|
|
|
|
|
|
|
/* Page number for multi-page functions. */
|
|
|
|
int mvs_page_num = 0;
|
|
|
|
|
|
|
|
/* Label node list anchor. */
|
|
|
|
static label_node_t *label_anchor = 0;
|
|
|
|
|
|
|
|
/* Label node free list anchor. */
|
|
|
|
static label_node_t *free_anchor = 0;
|
|
|
|
|
|
|
|
/* Assembler source file descriptor. */
|
|
|
|
static FILE *assembler_source = 0;
|
|
|
|
|
|
|
|
/* Define the length of the internal MVS function table. */
|
|
|
|
#define MVS_FUNCTION_TABLE_LENGTH 32
|
|
|
|
|
|
|
|
/* C/370 internal function table. These functions use non-standard linkage
|
|
|
|
and must handled in a special manner. */
|
|
|
|
static char *mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] =
|
|
|
|
{
|
|
|
|
"ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
|
|
|
|
"edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
|
|
|
|
"edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
|
|
|
|
"fabs", "floor", "fmod", "frexp", "hypot", "j0",
|
|
|
|
"j1", "jn", "ldexp", "modf", "pow", "y0",
|
|
|
|
"y1", "yn"
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ASCII to EBCDIC conversion table. */
|
|
|
|
#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
|
|
|
|
static unsigned char ascebc[256] =
|
|
|
|
{
|
|
|
|
/*00 NL SH SX EX ET NQ AK BL */
|
|
|
|
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
|
|
|
|
/*08 BS HT LF VT FF CR SO SI */
|
|
|
|
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
|
|
/*10 DL D1 D2 D3 D4 NK SN EB */
|
|
|
|
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
|
|
|
|
/*18 CN EM SB EC FS GS RS US */
|
|
|
|
0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
|
|
|
|
/*20 SP ! " # $ % & ' */
|
|
|
|
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
|
|
|
|
/*28 ( ) * + , - . / */
|
|
|
|
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
|
|
|
|
/*30 0 1 2 3 4 5 6 7 */
|
|
|
|
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
|
|
|
|
/*38 8 9 : ; < = > ? */
|
|
|
|
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
|
|
|
|
/*40 @ A B C D E F G */
|
|
|
|
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
|
|
|
|
/*48 H I J K L M N O */
|
|
|
|
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
|
|
|
|
/*50 P Q R S T U V W */
|
|
|
|
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
|
|
|
|
/*58 X Y Z [ \ ] ^ _ */
|
|
|
|
0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
|
|
|
|
/*60 ` a b c d e f g */
|
|
|
|
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
|
|
/*68 h i j k l m n o */
|
|
|
|
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
|
|
|
|
/*70 p q r s t u v w */
|
|
|
|
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
|
|
|
|
/*78 x y z { | } ~ DL */
|
|
|
|
0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
|
|
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* EBCDIC to ASCII conversion table. */
|
|
|
|
#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
|
|
|
|
unsigned char ebcasc[256] =
|
|
|
|
{
|
|
|
|
/*00 NU SH SX EX PF HT LC DL */
|
|
|
|
0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F,
|
|
|
|
/*08 SM VT FF CR SO SI */
|
|
|
|
0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
|
|
/*10 DE D1 D2 TM RS NL BS IL */
|
|
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x08, 0x00,
|
|
|
|
/*18 CN EM CC C1 FS GS RS US */
|
|
|
|
0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
|
|
|
|
/*20 DS SS FS BP LF EB EC */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
|
|
|
|
/*28 SM C2 EQ AK BL */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x00,
|
|
|
|
/*30 SY PN RS UC ET */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
|
|
|
/*38 C3 D4 NK SU */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
|
|
|
|
/*40 SP */
|
|
|
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*48 . < ( + | */
|
|
|
|
0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
|
|
|
/*50 & */
|
|
|
|
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*58 ! $ * ) ; ^ */
|
|
|
|
0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
|
|
|
|
/*60 - / */
|
|
|
|
0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*68 , % _ > ? */
|
|
|
|
0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
|
|
|
/*70 */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*78 ` : # @ ' = " */
|
|
|
|
0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
|
|
|
/*80 a b c d e f g */
|
|
|
|
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
|
|
/*88 h i { */
|
|
|
|
0x68, 0x69, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*90 j k l m n o p */
|
|
|
|
0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
|
|
|
/*98 q r } */
|
|
|
|
0x71, 0x72, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*A0 ~ s t u v w x */
|
|
|
|
0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
|
|
|
/*A8 y z [ */
|
|
|
|
0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
|
|
|
|
/*B0 */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*B8 ] */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
|
|
|
|
/*C0 { A B C D E F G */
|
|
|
|
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
|
|
/*C8 H I */
|
|
|
|
0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*D0 } J K L M N O P */
|
|
|
|
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
|
|
|
/*D8 Q R */
|
|
|
|
0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*E0 \ S T U V W X */
|
|
|
|
0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
|
|
/*E8 Y Z */
|
|
|
|
0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
/*F0 0 1 2 3 4 5 6 7 */
|
|
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
|
|
/*F8 8 9 */
|
|
|
|
0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Map characters from one character set to another.
|
|
|
|
C is the character to be translated. */
|
|
|
|
|
|
|
|
char
|
|
|
|
mvs_map_char (c)
|
|
|
|
char c;
|
|
|
|
{
|
|
|
|
#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
|
|
|
|
return ascebc[c];
|
|
|
|
#else
|
|
|
|
#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
|
|
|
|
return ebcasc[c];
|
|
|
|
#else
|
|
|
|
return c;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emit reload of base register if indicated. This is to eliminate multiple
|
|
|
|
reloads when several labels are generated pointing to the same place
|
|
|
|
in the code. */
|
|
|
|
|
|
|
|
int
|
|
|
|
check_label_emit (void)
|
|
|
|
{
|
|
|
|
if (mvs_label_emitted)
|
|
|
|
{
|
|
|
|
mvs_label_emitted = 0;
|
|
|
|
mvs_page_code += 4;
|
|
|
|
fprintf (assembler_source, "\tL\t%d,%d(,%d)\n",
|
|
|
|
BASE_REGISTER, (mvs_page_num - function_base_page) * 4,
|
|
|
|
PAGE_REGISTER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the label to the current page label list. If a free element is available
|
|
|
|
it will be used for the new label. Otherwise, a label element will be
|
|
|
|
allocated from memory.
|
|
|
|
ID is the label number of the label being added to the list. */
|
|
|
|
|
|
|
|
int
|
|
|
|
mvs_add_label (id)
|
|
|
|
int id;
|
|
|
|
{
|
|
|
|
label_node_t *lp;
|
|
|
|
|
|
|
|
if (free_anchor)
|
|
|
|
{
|
|
|
|
lp = free_anchor;
|
|
|
|
free_anchor = lp->label_next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lp = (label_node_t *) malloc (sizeof (label_node_t));
|
|
|
|
if (lp == 0)
|
|
|
|
{
|
|
|
|
fatal ("virtual memory exhausted\n");
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lp->label_id = id;
|
|
|
|
lp->label_page = mvs_page_num;
|
|
|
|
lp->label_next = label_anchor;
|
|
|
|
label_anchor = lp;
|
|
|
|
}
|
|
|
|
|
1998-08-16 21:35:45 +04:00
|
|
|
/* Check to see if the label is in the list. If 1 is returned then a load
|
1998-03-29 12:14:27 +04:00
|
|
|
and branch on register must be generated.
|
|
|
|
ID is the label number of the label being checked. */
|
|
|
|
|
|
|
|
int
|
|
|
|
mvs_check_label (id)
|
|
|
|
int id;
|
|
|
|
{
|
|
|
|
label_node_t *lp;
|
|
|
|
|
|
|
|
for (lp = label_anchor; lp; lp = lp->label_next)
|
|
|
|
{
|
|
|
|
if (lp->label_id == id)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The label list for the current page freed by linking the list onto the free
|
|
|
|
label element chain. */
|
|
|
|
|
|
|
|
int
|
|
|
|
mvs_free_label (void)
|
|
|
|
{
|
|
|
|
if (label_anchor)
|
|
|
|
{
|
|
|
|
if (free_anchor)
|
|
|
|
label_anchor->label_next = free_anchor;
|
|
|
|
free_anchor = label_anchor;
|
|
|
|
}
|
|
|
|
label_anchor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the page size limit is reached a new code page is started, and the base
|
|
|
|
register is set to it. This page break point is counted conservatively,
|
|
|
|
most literals that have the same value are collapsed by the assembler.
|
|
|
|
True is returned when a new page is started.
|
|
|
|
FILE is the assembler output file descriptor.
|
|
|
|
CODE is the length, in bytes, of the instruction to be emitted.
|
|
|
|
LIT is the length of the literal to be emitted. */
|
|
|
|
|
|
|
|
int
|
|
|
|
mvs_check_page (file, code, lit)
|
|
|
|
FILE *file;
|
|
|
|
int code, lit;
|
|
|
|
{
|
|
|
|
if (file)
|
|
|
|
assembler_source = file;
|
|
|
|
|
|
|
|
if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH)
|
|
|
|
{
|
|
|
|
fprintf (assembler_source, "\tB\tPGE%d\n", mvs_page_num);
|
|
|
|
fprintf (assembler_source, "\tDS\t0F\n");
|
|
|
|
fprintf (assembler_source, "\tLTORG\n");
|
|
|
|
fprintf (assembler_source, "\tDS\t0F\n");
|
|
|
|
fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num);
|
|
|
|
fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER);
|
|
|
|
mvs_page_num++;
|
|
|
|
fprintf (assembler_source, "\tBALR\t%d,0\n", BASE_REGISTER);
|
|
|
|
fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num);
|
|
|
|
fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER);
|
|
|
|
mvs_free_label ();
|
|
|
|
mvs_page_code = code;
|
|
|
|
mvs_page_lit = lit;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
mvs_page_code += code;
|
|
|
|
mvs_page_lit += lit;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for C/370 runtime function, they don't use standard calling
|
|
|
|
conventions. True is returned if the function is in the table.
|
|
|
|
NAME is the name of the current function. */
|
|
|
|
|
|
|
|
int
|
|
|
|
mvs_function_check (name)
|
|
|
|
char *name;
|
|
|
|
{
|
|
|
|
int lower, middle, upper;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
lower = 0;
|
|
|
|
upper = MVS_FUNCTION_TABLE_LENGTH - 1;
|
|
|
|
while (lower <= upper)
|
|
|
|
{
|
|
|
|
middle = (lower + upper) / 2;
|
|
|
|
i = strcmp (name, mvs_function_table[middle]);
|
|
|
|
if (i == 0)
|
|
|
|
return 1;
|
|
|
|
if (i < 0)
|
|
|
|
upper = middle - 1;
|
|
|
|
else
|
|
|
|
lower = middle + 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
|
|
|
|
OP is the current operation.
|
|
|
|
MODE is the current operation mode. */
|
|
|
|
|
|
|
|
int
|
|
|
|
s_operand (op, mode)
|
|
|
|
register rtx op;
|
|
|
|
enum machine_mode mode;
|
|
|
|
{
|
|
|
|
extern int volatile_ok;
|
|
|
|
register enum rtx_code code = GET_CODE (op);
|
|
|
|
|
|
|
|
if (CONSTANT_ADDRESS_P (op))
|
|
|
|
return 1;
|
|
|
|
if (mode == VOIDmode || GET_MODE (op) != mode)
|
|
|
|
return 0;
|
|
|
|
if (code == MEM)
|
|
|
|
{
|
|
|
|
register rtx x = XEXP (op, 0);
|
|
|
|
|
|
|
|
if (!volatile_ok && op->volatil)
|
|
|
|
return 0;
|
|
|
|
if (REG_P (x) && REG_OK_FOR_BASE_P (x))
|
|
|
|
return 1;
|
|
|
|
if (GET_CODE (x) == PLUS
|
|
|
|
&& REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
|
|
|
|
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
|
|
&& (unsigned) INTVAL (XEXP (x, 1)) < 4096)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
|
|
|
|
instruction.
|
|
|
|
OP is the current operation.
|
|
|
|
MODE is the current operation mode. */
|
|
|
|
|
|
|
|
int
|
|
|
|
r_or_s_operand (op, mode)
|
|
|
|
register rtx op;
|
|
|
|
enum machine_mode mode;
|
|
|
|
{
|
|
|
|
extern int volatile_ok;
|
|
|
|
register enum rtx_code code = GET_CODE (op);
|
|
|
|
|
|
|
|
if (CONSTANT_ADDRESS_P (op))
|
|
|
|
return 1;
|
|
|
|
if (mode == VOIDmode || GET_MODE (op) != mode)
|
|
|
|
return 0;
|
|
|
|
if (code == REG)
|
|
|
|
return 1;
|
|
|
|
else if (code == MEM)
|
|
|
|
{
|
|
|
|
register rtx x = XEXP (op, 0);
|
|
|
|
|
|
|
|
if (!volatile_ok && op->volatil)
|
|
|
|
return 0;
|
|
|
|
if (REG_P (x) && REG_OK_FOR_BASE_P (x))
|
|
|
|
return 1;
|
|
|
|
if (GET_CODE (x) == PLUS
|
|
|
|
&& REG_P (XEXP (x, 0)) && REG_OK_FOR_BASE_P (XEXP (x, 0))
|
|
|
|
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
|
|
|
&& (unsigned) INTVAL (XEXP (x, 1)) < 4096)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return 1 if the next instruction is an unsigned jump instruction.
|
|
|
|
INSN is the current instruction. */
|
|
|
|
|
|
|
|
unsigned_jump_follows_p (insn)
|
|
|
|
register rtx insn;
|
|
|
|
{
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
if (GET_CODE (insn) != JUMP_INSN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
insn = XEXP (insn, 3);
|
|
|
|
if (GET_CODE (insn) != SET)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (GET_CODE (XEXP (insn, 0)) != PC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
insn = XEXP (insn, 1);
|
|
|
|
if (GET_CODE (insn) != IF_THEN_ELSE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
insn = XEXP (insn, 0);
|
|
|
|
return GET_CODE (insn) != GE && GET_CODE (insn) != GT
|
|
|
|
&& GET_CODE (insn) != LE && GET_CODE (insn) != LT;
|
|
|
|
}
|
1998-08-16 21:35:45 +04:00
|
|
|
|
|
|
|
void
|
|
|
|
i370_function_prolog (f, l)
|
|
|
|
FILE *f;
|
|
|
|
int l;
|
|
|
|
{
|
|
|
|
#if MACROPROLOGUE == 1
|
|
|
|
fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
|
|
|
|
STACK_POINTER_OFFSET + l - 120 +
|
|
|
|
current_function_outgoing_args_size, BASE_REGISTER);
|
|
|
|
fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
|
|
|
|
fprintf (f, "\tLR\t11,1\n");
|
|
|
|
fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num);
|
|
|
|
mvs_page_code = 6;
|
|
|
|
mvs_page_lit = 4;
|
|
|
|
mvs_check_page (f, 0, 0);
|
|
|
|
function_base_page = mvs_page_num;
|
|
|
|
#else /* MACROPROLOGUE != 1 */
|
|
|
|
static int function_label_index = 1;
|
|
|
|
static int function_first = 0;
|
|
|
|
static int function_year, function_month, function_day;
|
|
|
|
static int function_hour, function_minute, function_second;
|
|
|
|
int i;
|
|
|
|
if (!function_first)
|
|
|
|
{
|
|
|
|
struct tm *function_time;
|
|
|
|
time_t lcltime;
|
|
|
|
time (&lcltime);
|
|
|
|
function_time = localtime (&lcltime);
|
|
|
|
function_year = function_time->tm_year + 1900;
|
|
|
|
function_month = function_time->tm_mon + 1;
|
|
|
|
function_day = function_time->tm_mday;
|
|
|
|
function_hour = function_time->tm_hour;
|
|
|
|
function_minute = function_time->tm_min;
|
|
|
|
function_second = function_time->tm_sec;
|
|
|
|
fprintf (f, "PPA2\tDS\t0F\n");
|
|
|
|
fprintf (f, "\tDC\tX'03',X'00',X'33',X'00'\n");
|
|
|
|
fprintf (f, "\tDC\tV(CEESTART),A(0)\n");
|
|
|
|
fprintf (f, "\tDC\tA(CEETIMES)\n");
|
|
|
|
fprintf (f, "CEETIMES\tDS\t0F\n");
|
|
|
|
fprintf (f, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
|
|
|
|
function_year, function_month, function_day,
|
|
|
|
function_hour, function_minute, function_second);
|
|
|
|
fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
|
|
|
|
}
|
|
|
|
fprintf (f, "$DSD%03d\tDSECT\n", function_label_index);
|
|
|
|
fprintf (f, "\tDS\tD\n");
|
|
|
|
fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l
|
|
|
|
+ current_function_outgoing_args_size);
|
|
|
|
fprintf (f, "\tORG\t$DSD%03d\n", function_label_index);
|
|
|
|
fprintf (f, "\tDS\tCL(120+8)\n");
|
|
|
|
fprintf (f, "\tORG\n");
|
|
|
|
fprintf (f, "\tDS\t0D\n");
|
|
|
|
fprintf (f, "$DSL%03d\tEQU\t*-$DSD%03d-8\n", function_label_index,
|
|
|
|
function_label_index);
|
|
|
|
fprintf (f, "\tDS\t0H\n");
|
|
|
|
assemble_name (f, mvs_function_name);
|
|
|
|
fprintf (f, "\tEQU\t*\n");
|
|
|
|
fprintf (f, "\tUSING\t*,15\n");
|
|
|
|
fprintf (f, "\tB\tFPL%03d\n", function_label_index);
|
|
|
|
fprintf (f, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index + 1);
|
|
|
|
fprintf (f, "\tDC\tX'CE',X'A0',AL1(16)\n");
|
|
|
|
fprintf (f, "\tDC\tAL4(PPA2)\n");
|
|
|
|
fprintf (f, "\tDC\tAL4(0)\n");
|
|
|
|
fprintf (f, "\tDC\tAL4($DSL%03d)\n", function_label_index);
|
|
|
|
fprintf (f, "FPL%03d\tEQU\t*\n", function_label_index + 1);
|
|
|
|
fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
|
|
|
|
mvs_function_name);
|
|
|
|
fprintf (f, "FPL%03d\tDS\t0H\n", function_label_index);
|
|
|
|
fprintf (f, "\tSTM\t14,12,12(13)\n");
|
|
|
|
fprintf (f, "\tL\t2,76(,13)\n");
|
|
|
|
fprintf (f, "\tL\t0,16(,15)\n");
|
|
|
|
fprintf (f, "\tALR\t0,2\n");
|
|
|
|
fprintf (f, "\tCL\t0,12(,12)\n");
|
|
|
|
fprintf (f, "\tBNH\t*+10\n");
|
|
|
|
fprintf (f, "\tL\t15,116(,12)\n");
|
|
|
|
fprintf (f, "\tBALR\t14,15\n");
|
|
|
|
fprintf (f, "\tL\t15,72(,13)\n");
|
|
|
|
fprintf (f, "\tSTM\t15,0,72(2)\n");
|
|
|
|
fprintf (f, "\tMVI\t0(2),X'10'\n");
|
|
|
|
fprintf (f, "\tST\t2,8(,13)\n ");
|
|
|
|
fprintf (f, "\tST\t13,4(,2)\n ");
|
|
|
|
fprintf (f, "\tLR\t13,2\n");
|
|
|
|
fprintf (f, "\tDROP\t15\n");
|
|
|
|
fprintf (f, "\tBALR\t%d,0\n", BASE_REGISTER);
|
|
|
|
fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
|
|
|
|
fprintf (f, "\tUSING\t*,%d\n", BASE_REGISTER);
|
|
|
|
fprintf (f, "\tLR\t11,1\n");
|
|
|
|
fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num);
|
|
|
|
mvs_page_code = 4;
|
|
|
|
mvs_page_lit = 4;
|
|
|
|
mvs_check_page (f, 0, 0);
|
|
|
|
function_base_page = mvs_page_num;
|
|
|
|
function_first = 1;
|
|
|
|
function_label_index += 2;
|
|
|
|
#endif /* MACROPROLOGUE */
|
|
|
|
}
|