#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "function.h"
#include "expr.h"
#include "flags.h"
#include "recog.h"
#include "toplev.h"
#include "cpplib.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
extern FILE *asm_out_file;
typedef struct label_node
{
struct label_node *label_next;
int label_id;
int label_page;
int first_ref_page;
int label_addr;
int label_first_ref;
int label_last_ref;
}
label_node_t;
int mvs_need_base_reload = 0;
int function_base_page;
int mvs_page_code;
int mvs_page_lit;
char *mvs_function_name = 0;
int mvs_function_name_length = 0;
int mvs_page_num = 0;
static label_node_t *label_anchor = 0;
static label_node_t *free_anchor = 0;
static FILE *assembler_source = 0;
static label_node_t * mvs_get_label PARAMS ((int));
static void i370_label_scan PARAMS ((void));
#ifdef TARGET_HLASM
static bool i370_hlasm_assemble_integer PARAMS ((rtx, unsigned int, int));
static void i370_globalize_label PARAMS ((FILE *, const char *));
#endif
static void i370_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void i370_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
#ifdef LONGEXTERNAL
static int mvs_hash_alias PARAMS ((const char *));
#endif
static void i370_encode_section_info PARAMS ((tree, int));
#ifdef TARGET_HLASM
#define MVS_HASH_PRIME 999983
#if defined(HOST_EBCDIC)
#define MVS_SET_SIZE 256
#else
#define MVS_SET_SIZE 128
#endif
#ifndef MAX_MVS_LABEL_SIZE
#define MAX_MVS_LABEL_SIZE 8
#endif
#define MAX_LONG_LABEL_SIZE 255
typedef struct alias_node
{
struct alias_node *alias_next;
int alias_emitted;
char alias_name [MAX_MVS_LABEL_SIZE + 1];
char real_name [MAX_LONG_LABEL_SIZE + 1];
}
alias_node_t;
static alias_node_t *alias_anchor = 0;
#define MVS_FUNCTION_TABLE_LENGTH 32
static const char *const mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] =
{
#if defined(HOST_EBCDIC)
"ceil", "edc_acos", "edc_asin", "edc_atan", "edc_ata2", "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", "jn",
"j0", "j1", "ldexp", "modf", "pow", "yn",
"y0", "y1"
#else
"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"
#endif
};
#endif
static const unsigned char ascebc[256] =
{
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
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
};
static const unsigned char ebcasc[256] =
{
0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7F,
0x00, 0x00, 0x00, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x08, 0x00,
0x18, 0x19, 0x00, 0x00, 0x1C, 0x1D, 0x1E, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x17, 0x1B,
0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1A,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00,
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
};
#ifdef TARGET_HLASM
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP NULL
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP NULL
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP NULL
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER i370_hlasm_assemble_integer
#undef TARGET_ASM_GLOBALIZE_LABEL
#define TARGET_ASM_GLOBALIZE_LABEL i370_globalize_label
#endif
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE i370_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE i370_output_function_epilogue
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO i370_encode_section_info
struct gcc_target targetm = TARGET_INITIALIZER;
void
override_options ()
{
memset (real_format_for_mode, 0, sizeof real_format_for_mode);
real_format_for_mode[SFmode - QFmode] = &i370_single_format;
real_format_for_mode[DFmode - QFmode] = &i370_double_format;
}
char
mvs_map_char (c)
int c;
{
#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
fprintf (stderr, "mvs_map_char: TE & !HE: c = %02x\n", c);
return ascebc[c];
#else
#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
fprintf (stderr, "mvs_map_char: !TE & HE: c = %02x\n", c);
return ebcasc[c];
#else
fprintf (stderr, "mvs_map_char: !TE & !HE: c = %02x\n", c);
return c;
#endif
#endif
}
int
i370_branch_dest (branch)
rtx branch;
{
rtx dest = SET_SRC (PATTERN (branch));
int dest_uid;
int dest_addr;
if (GET_CODE (dest) == IF_THEN_ELSE)
dest = XEXP (dest, 1);
dest = XEXP (dest, 0);
dest_uid = INSN_UID (dest);
dest_addr = INSN_ADDRESSES (dest_uid);
{
label_node_t *lp;
rtx label = JUMP_LABEL (branch);
int labelno = CODE_LABEL_NUMBER (label);
if (!label || CODE_LABEL != GET_CODE (label)) abort ();
lp = mvs_get_label (labelno);
if (-1 == lp -> first_ref_page) lp->first_ref_page = mvs_page_num;
}
return dest_addr;
}
int
i370_branch_length (insn)
rtx insn;
{
int here, there;
here = INSN_ADDRESSES (INSN_UID (insn));
there = i370_branch_dest (insn);
return (there - here);
}
int
i370_short_branch (insn)
rtx insn;
{
int base_offset;
base_offset = i370_branch_length(insn);
if (0 > base_offset)
{
base_offset += mvs_page_code;
}
else
{
base_offset *= 2;
base_offset += mvs_page_code + mvs_page_lit;
}
if ((4060 >base_offset) && ( 0 < base_offset)) return 1;
return 0;
}
#define I370_RECORD_LABEL_REF(label,addr) { \
label_node_t *lp; \
int labelno = CODE_LABEL_NUMBER (label); \
lp = mvs_get_label (labelno); \
if (addr < lp -> label_first_ref) lp->label_first_ref = addr; \
if (addr > lp -> label_last_ref) lp->label_last_ref = addr; \
}
static void
i370_label_scan ()
{
rtx insn;
label_node_t *lp;
int tablejump_offset = 0;
for (insn = get_insns(); insn; insn = NEXT_INSN(insn))
{
int here = INSN_ADDRESSES (INSN_UID (insn));
enum rtx_code code = GET_CODE(insn);
here += tablejump_offset;
INSN_ADDRESSES (INSN_UID (insn)) = here;
if (CODE_LABEL == code)
{
int labelno = CODE_LABEL_NUMBER (insn);
lp = mvs_get_label (labelno);
lp -> label_addr = here;
#if 0
rtx labelref = LABEL_REFS (insn);
rtx ref = labelref;
do
{
rtx linsn = CONTAINING_INSN(ref);
ref = LABEL_NEXTREF(ref);
} while (ref && (ref != labelref));
#endif
}
else
if (JUMP_INSN == code)
{
rtx label = JUMP_LABEL (insn);
if (!label)
{
int j;
rtx body = PATTERN (insn);
if (ADDR_VEC == GET_CODE(body))
{
for (j=0; j < XVECLEN (body, 0); j++)
{
rtx lref = XVECEXP (body, 0, j);
if (LABEL_REF != GET_CODE (lref)) abort ();
label = XEXP (lref,0);
if (CODE_LABEL != GET_CODE (label)) abort ();
tablejump_offset += 4;
here += 4;
I370_RECORD_LABEL_REF(label,here);
}
continue;
}
else
if (ADDR_DIFF_VEC == GET_CODE(body))
{
debug_rtx (insn);
for (j=0; j < XVECLEN (body, 0); j++)
{
}
continue;
}
else
{
debug_rtx (insn);
continue;
}
}
else
{
if (CODE_LABEL != GET_CODE (label)) abort ();
I370_RECORD_LABEL_REF(label,here);
}
}
else
if (INSN == code)
{
if ('i' == GET_RTX_CLASS (code))
{
rtx note;
for (note = REG_NOTES (insn); note; note = XEXP(note,1))
{
if (REG_LABEL == REG_NOTE_KIND(note))
{
rtx label = XEXP (note,0);
if (!label || CODE_LABEL != GET_CODE (label)) abort ();
I370_RECORD_LABEL_REF(label,here);
}
}
}
}
}
}
void
check_label_emit ()
{
if (mvs_need_base_reload)
{
mvs_need_base_reload = 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);
}
}
static label_node_t *
mvs_get_label (id)
int id;
{
label_node_t *lp;
for (lp = label_anchor; lp; lp = lp->label_next)
{
if (lp->label_id == id) return lp;
}
if (free_anchor)
{
lp = free_anchor;
free_anchor = lp->label_next;
}
else
{
lp = (label_node_t *) xmalloc (sizeof (label_node_t));
}
lp->label_id = id;
lp->label_page = -1;
lp->label_next = label_anchor;
lp->label_first_ref = 2000123123;
lp->label_last_ref = -1;
lp->label_addr = -1;
lp->first_ref_page = -1;
label_anchor = lp;
return lp;
}
void
mvs_add_label (id)
int id;
{
label_node_t *lp;
int fwd_distance;
lp = mvs_get_label (id);
lp->label_page = mvs_page_num;
if ((-1 != lp->first_ref_page) &&
(lp->first_ref_page != mvs_page_num))
{
mvs_need_base_reload ++;
return;
}
if (lp->label_last_ref < lp->label_addr) return;
fwd_distance = lp->label_last_ref - lp->label_addr;
if (mvs_page_code + 2 * fwd_distance + mvs_page_lit < 4060) return;
mvs_need_base_reload ++;
}
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)
{
if (lp->label_page == mvs_page_num)
{
return 1;
}
else
{
return 0;
}
}
}
return 0;
}
#if 0
int
mvs_get_label_page(int id)
{
label_node_t *lp;
for (lp = label_anchor; lp; lp = lp->label_next)
{
if (lp->label_id == id)
return lp->label_page;
}
return -1;
}
#endif
void
mvs_free_label_list ()
{
if (label_anchor)
{
label_node_t *last_lp = label_anchor;
while (last_lp->label_next) last_lp = last_lp->label_next;
last_lp->label_next = free_anchor;
free_anchor = label_anchor;
}
label_anchor = 0;
}
#ifdef TARGET_HLASM
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, "\tBASR\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_page_code = code;
mvs_page_lit = lit;
return 1;
}
mvs_page_code += code;
mvs_page_lit += lit;
return 0;
}
#endif
#ifdef TARGET_ELF_ABI
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\t.LPGE%d\n", mvs_page_num);
fprintf (assembler_source, "\t.balign\t4\n");
fprintf (assembler_source, "\t.LTORG\n");
fprintf (assembler_source, "\t.balign\t4\n");
fprintf (assembler_source, ".LPGE%d:\n", mvs_page_num);
fprintf (assembler_source, "\t.DROP\t%d\n", BASE_REGISTER);
mvs_page_num++;
fprintf (assembler_source, "\tBASR\tr%d,0\n", BASE_REGISTER);
fprintf (assembler_source, ".LPG%d:\n", mvs_page_num);
fprintf (assembler_source, "\t.USING\t.,r%d\n", BASE_REGISTER);
mvs_page_code = code;
mvs_page_lit = lit;
return 1;
}
mvs_page_code += code;
mvs_page_lit += lit;
return 0;
}
#endif
#ifdef TARGET_HLASM
int
mvs_function_check (name)
const 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;
}
#ifdef LONGEXTERNAL
static int
mvs_hash_alias (key)
const char *key;
{
int h;
int i;
int l = strlen (key);
h = key[0];
for (i = 1; i < l; i++)
h = ((h * MVS_SET_SIZE) + key[i]) % MVS_HASH_PRIME;
return (h);
}
#endif
void
mvs_add_alias (realname, aliasname, emitted)
const char *realname;
const char *aliasname;
int emitted;
{
alias_node_t *ap;
ap = (alias_node_t *) xmalloc (sizeof (alias_node_t));
if (strlen (realname) > MAX_LONG_LABEL_SIZE)
{
warning ("real name is too long - alias ignored");
return;
}
if (strlen (aliasname) > MAX_MVS_LABEL_SIZE)
{
warning ("alias name is too long - alias ignored");
return;
}
strcpy (ap->real_name, realname);
strcpy (ap->alias_name, aliasname);
ap->alias_emitted = emitted;
ap->alias_next = alias_anchor;
alias_anchor = ap;
}
int
mvs_need_alias (realname)
const char *realname;
{
int i, j = strlen (realname);
if (mvs_function_check (realname))
return 0;
#if 0
if (!strcmp (realname, "gccmain"))
return 0;
if (!strcmp (realname, "main"))
return 0;
#endif
if (j > MAX_MVS_LABEL_SIZE)
return 1;
if (strchr (realname, '_') != 0)
return 1;
if (ISUPPER (realname[0]))
{
for (i = 1; i < j; i++)
{
if (ISLOWER (realname[i]))
return 1;
}
}
else
{
for (i = 1; i < j; i++)
{
if (ISUPPER (realname[i]))
return 1;
}
}
return 0;
}
int
mvs_get_alias (realname, aliasname)
const char *realname;
char *aliasname;
{
#ifdef LONGEXTERNAL
alias_node_t *ap;
for (ap = alias_anchor; ap; ap = ap->alias_next)
{
if (!strcmp (ap->real_name, realname))
{
strcpy (aliasname, ap->alias_name);
return 1;
}
}
if (mvs_need_alias (realname))
{
char c1, c2;
c1 = realname[0];
c2 = realname[1];
if (ISLOWER (c1)) c1 = TOUPPER (c1);
else if (c1 == '_') c1 = 'A';
if (ISLOWER (c2)) c2 = TOUPPER (c2);
else if (c2 == '_' || c2 == '\0') c2 = '#';
sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname));
mvs_add_alias (realname, aliasname, 0);
return 1;
}
#else
if (strlen (realname) > MAX_MVS_LABEL_SIZE)
{
strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE);
aliasname[MAX_MVS_LABEL_SIZE] = '\0';
return 1;
}
#endif
return 0;
}
int
mvs_check_alias (realname, aliasname)
const char *realname;
char *aliasname;
{
#ifdef LONGEXTERNAL
alias_node_t *ap;
for (ap = alias_anchor; ap; ap = ap->alias_next)
{
if (!strcmp (ap->real_name, realname))
{
int rc = (ap->alias_emitted == 1) ? 1 : 2;
strcpy (aliasname, ap->alias_name);
ap->alias_emitted = 1;
return rc;
}
}
if (mvs_need_alias (realname))
{
char c1, c2;
c1 = realname[0];
c2 = realname[1];
if (ISLOWER (c1)) c1 = TOUPPER (c1);
else if (c1 == '_') c1 = 'A';
if (ISLOWER (c2)) c2 = TOUPPER (c2);
else if (c2 == '_' || c2 == '\0') c2 = '#';
sprintf (aliasname, "%c%c%06d", c1, c2, mvs_hash_alias (realname));
mvs_add_alias (realname, aliasname, 0);
alias_anchor->alias_emitted = 1;
return 2;
}
#else
if (strlen (realname) > MAX_MVS_LABEL_SIZE)
{
strncpy (aliasname, realname, MAX_MVS_LABEL_SIZE);
aliasname[MAX_MVS_LABEL_SIZE] = '\0';
return 1;
}
#endif
return 0;
}
#endif
#ifdef TARGET_ELF_ABI
int
mvs_function_check (name)
const char *name ATTRIBUTE_UNUSED;
{
return 0;
}
#endif
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;
}
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;
}
int
unsigned_jump_follows_p (insn)
register rtx insn;
{
rtx orig_insn = insn;
while (1)
{
register rtx tmp_insn;
enum rtx_code coda;
insn = NEXT_INSN (insn);
if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn);
if (GET_CODE (insn) != JUMP_INSN) continue;
tmp_insn = XEXP (insn, 3);
if (GET_CODE (tmp_insn) != SET) continue;
if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue;
tmp_insn = XEXP (tmp_insn, 1);
if (GET_CODE (tmp_insn) != IF_THEN_ELSE) continue;
tmp_insn = XEXP (tmp_insn, 0);
coda = GET_CODE (tmp_insn);
return coda != GE && coda != GT && coda != LE && coda != LT;
}
}
#ifdef TARGET_HLASM
static bool
i370_hlasm_assemble_integer (x, size, aligned_p)
rtx x;
unsigned int size;
int aligned_p;
{
const char *int_format = NULL;
if (aligned_p)
switch (size)
{
case 1:
int_format = "\tDC\tX'%02X'\n";
break;
case 2:
int_format = "\tDC\tX'%04X'\n";
break;
case 4:
if (GET_CODE (x) == CONST_INT)
{
fputs ("\tDC\tF'", asm_out_file);
output_addr_const (asm_out_file, x);
fputs ("'\n", asm_out_file);
}
else
{
fputs ("\tDC\tA(", asm_out_file);
output_addr_const (asm_out_file, x);
fputs (")\n", asm_out_file);
}
return true;
}
if (int_format && GET_CODE (x) == CONST_INT)
{
fprintf (asm_out_file, int_format, INTVAL (x));
return true;
}
return default_assemble_integer (x, size, aligned_p);
}
static void
i370_output_function_prologue (f, l)
FILE *f;
HOST_WIDE_INT l;
{
#if MACROPROLOGUE == 1
fprintf (f, "* Function %s prologue\n", mvs_function_name);
fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
STACK_POINTER_OFFSET + l - 120 +
current_function_outgoing_args_size, BASE_REGISTER);
#else
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;
#if defined(LE370)
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, "* Function %s prologue\n", mvs_function_name);
fprintf (f, "FDSE%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\tFDSE%03d\n", function_label_index);
fprintf (f, "\tDS\tCL(120+8)\n");
fprintf (f, "\tORG\n");
fprintf (f, "\tDS\t0D\n");
fprintf (f, "FDSL%03d\tEQU\t*-FDSE%03d-8\n", function_label_index,
function_label_index);
fprintf (f, "\tDS\t0H\n");
assemble_name (f, mvs_function_name);
fprintf (f, "\tCSECT\n");
fprintf (f, "\tUSING\t*,15\n");
fprintf (f, "\tB\tFENT%03d\n", function_label_index);
fprintf (f, "\tDC\tAL1(FNAM%03d+4-*)\n", function_label_index);
fprintf (f, "\tDC\tX'CE',X'A0',AL1(16)\n");
fprintf (f, "\tDC\tAL4(FPPA%03d)\n", function_label_index);
fprintf (f, "\tDC\tAL4(0)\n");
fprintf (f, "\tDC\tAL4(FDSL%03d)\n", function_label_index);
fprintf (f, "FNAM%03d\tEQU\t*\n", function_label_index);
fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
mvs_function_name);
fprintf (f, "FPPA%03d\tDS\t0F\n", function_label_index);
fprintf (f, "\tDC\tX'03',X'00',X'33',X'00'\n");
fprintf (f, "\tDC\tV(CEESTART)\n");
fprintf (f, "\tDC\tAL4(0)\n");
fprintf (f, "\tDC\tAL4(FTIM%03d)\n", function_label_index);
fprintf (f, "FTIM%03d\tDS\t0F\n", function_label_index);
fprintf (f, "\tDC\tCL4'%d',CL4'%02d%02d',CL6'%02d%02d00'\n",
function_year, function_month, function_day,
function_hour, function_minute);
fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
fprintf (f, "FENT%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, "\tUSING\t*,%d\n", BASE_REGISTER);
function_first = 1;
function_label_index ++;
#else
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, "* Function %s prologue\n", mvs_function_name);
fprintf (f, "FDSD%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\tFDSD%03d\n", function_label_index);
fprintf (f, "\tDS\tCL(120+8)\n");
fprintf (f, "\tORG\n");
fprintf (f, "\tDS\t0D\n");
fprintf (f, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index,
function_label_index);
fprintf (f, "\tDS\t0H\n");
assemble_name (f, mvs_function_name);
fprintf (f, "\tCSECT\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(FDSL%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, "\tUSING\t*,%d\n", BASE_REGISTER);
function_first = 1;
function_label_index += 2;
#endif
#endif
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);
fprintf (f, "* Function %s code\n", mvs_function_name);
mvs_free_label_list ();
mvs_page_code = 6;
mvs_page_lit = 4;
mvs_check_page (f, 0, 0);
function_base_page = mvs_page_num;
i370_label_scan ();
}
static void
i370_globalize_label (stream, name)
FILE *stream;
const char *name;
{
char temp[MAX_MVS_LABEL_SIZE + 1];
if (mvs_check_alias (name, temp) == 2)
fprintf (stream, "%s\tALIAS\tC'%s'\n", temp, name);
fputs ("\tENTRY\t", stream);
assemble_name (stream, name);
putc ('\n', stream);
}
#endif
#ifdef TARGET_ELF_ABI
static void
i370_output_function_prologue (f, frame_size)
FILE *f;
HOST_WIDE_INT frame_size;
{
static int function_label_index = 1;
static int function_first = 0;
int stackframe_size, aligned_size;
fprintf (f, "# Function prologue\n");
stackframe_size =
STACK_POINTER_OFFSET + current_function_outgoing_args_size + frame_size;
aligned_size = (stackframe_size + 7) >> 3;
aligned_size <<= 3;
fprintf (f, "# arg_size=0x%x frame_size=0x%x aligned size=0x%x\n",
current_function_outgoing_args_size, frame_size, aligned_size);
fprintf (f, "\t.using\t.,r15\n");
fprintf (f, "\tB\t.LFENT%03d\n", function_label_index);
fprintf (f, "\t.long\t%d\n", aligned_size);
fprintf (f, "\t.balign 2\n.LFENT%03d:\n",
function_label_index);
fprintf (f, "\tSTM\tr14,r12,12(sp)\n");
fprintf (f, "\tLR\tr3,sp\n");
fprintf (f, "\tSL\tsp,4(,r15)\n");
fprintf (f, "\tLR\tr11,r2\n");
fprintf (f, "\tST\tr3,4(,sp)\n ");
fprintf (f, "\t.drop\tr15\n");
fprintf (f, "\tBASR\tr%d,0\n", BASE_REGISTER);
fprintf (f, "\t.using\t.,r%d\n", BASE_REGISTER);
function_first = 1;
function_label_index ++;
fprintf (f, ".LPG%d:\n", mvs_page_num );
fprintf (f, "\tL\tr%d,=A(.LPGT%d)\n", PAGE_REGISTER, mvs_page_num);
fprintf (f, "# Function code\n");
mvs_free_label_list ();
mvs_page_code = 6;
mvs_page_lit = 4;
mvs_check_page (f, 0, 0);
function_base_page = mvs_page_num;
i370_label_scan ();
}
#endif
static void
i370_output_function_epilogue (file, l)
FILE *file;
HOST_WIDE_INT l ATTRIBUTE_UNUSED;
{
int i;
check_label_emit ();
mvs_check_page (file, 14, 0);
fprintf (file, "* Function %s epilogue\n", mvs_function_name);
mvs_page_num++;
#if MACROEPILOGUE == 1
fprintf (file, "\tEDCEPIL\n");
#else
fprintf (file, "\tL\t13,4(,13)\n");
fprintf (file, "\tL\t14,12(,13)\n");
fprintf (file, "\tLM\t2,12,28(13)\n");
fprintf (file, "\tBALR\t1,14\n");
fprintf (file, "\tDC\tA(");
assemble_name (file, mvs_function_name);
fprintf (file, ")\n" );
#endif
fprintf (file, "* Function %s literal pool\n", mvs_function_name);
fprintf (file, "\tDS\t0F\n" );
fprintf (file, "\tLTORG\n");
fprintf (file, "* Function %s page table\n", mvs_function_name);
fprintf (file, "\tDS\t0F\n");
fprintf (file, "PGT%d\tEQU\t*\n", function_base_page);
mvs_free_label_list();
for (i = function_base_page; i < mvs_page_num; i++)
fprintf (file, "\tDC\tA(PG%d)\n", i);
}
static void
i370_encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
if (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
}