Commit 92d6db66 by Linas Vepstas Committed by Richard Henderson

Bulk patch from Linas.

From-SVN: r28178
parent 14eee794
1999-07-19 Linas Vepstas <linas@linas.org>
* config/i370/README: New file.
* config/i370/linux.h: New file.
* config/i370/mvs.h: New file.
* config/i370/oe.h: New file.
* config/i370/t-linux: New file.
* config/i370/t-mvs: New file.
* config/i370/t-oe: New file.
* config/i370/x-oe: New file.
* config/i370/xm-linux.h: New file.
* config/i370/xm-mvs.h: New file.
* config/i370/xm-oe.h: New file.
* i370.c (label_node_t): Add first_ref_page, label_addr,
label_first_ref, label_last_ref members.
(mvs_need_base_reload): Renamed from mvs_label_emitted.
(MAX_MVS_LABEL_SIZE): Define.
(MAX_LONG_LABEL_SIZE): Define.
(alias_node_t, alias_anchor, alias_number): New.
(mvs_function_table): Reorder for EBCDIC.
(ascebc, ebcasc): Unconditionally define.
(i370_branch_dest, i370_branch_length): New functions.
(i370_short_branch, i370_label_scan): New functions.
(mvs_get_label): Renamed from mvs_add_label. Search for
an existing label before creating a new one.
(mvs_add_label): New function.
(mvs_get_label_page): New function.
(mvs_free_label_list): Renamed from mvs_free_label. Iterate
over the entire list.
(mvs_check_page) [TARGET_HLASM]: Use BASR not BALR.
(mvs_check_page) [TARGET_ELF_ABI]: New function.
(mvs_add_alias, mvs_need_alias): New functions.
(mvs_get_alias, mvs_check_alias): New functions.
(handle_pragma): New function.
(mvs_function_check): New function.
(unsigned_jump_follows_p): Search harder.
(i370_function_prolog) [TARGET_HLASM]: Handle LE370. Scan labels.
(i370_function_prolog) [TARGET_ELF_ABI]: New function.
* i370.h (TARGET_VERSION): Delete.
(CPP_SPEC, CPP_PREDEFINES): Delete.
(mvs_label_emitted): Delete.
(TARGET_EBCDIC): Delete.
(MAP_CHARACTER): Define only if TARGET_EBCDIC.
(HANDLE_PRAGMA): Define.
(HARD_REGNO_NREGS): Handle complex modes.
(HARD_REGNO_MODE_OK): Likewise.
(CLASS_MAX_NREGS): Likewise.
(RET_REG): Likewise.
(EXTRA_CONSTRAINT): Define.
(RETURN_IN_MEMORY): True for DImode.
(TRAMPOLINE_TEMPLATE): Use gen_rtx instead of GEN_INT.
(FUNCTION_PROFILER): Delete.
(COUNT_REGS): Fail if REG_P but not REG_OK_FOR_BASE_P.
(NOTICE_UPDATE_CC): Correct handling of MULT, DIV, logicals and shifts.
(TARGET_ESC, TARGET_BELL): Conditionally define for TARGET_EBCDIC.
(TARGET_BS, TARGET_TAB, TARGET_NEWLINE): Likewise.
(TARGET_VT, TARGET_FF, TARGET_CR): Likewise.
(ASM_FILE_START): Add "RMODE ANY".
(ASM_OUTPUT_EXTERNAL): Check for aliases.
(ASM_GLOBALIZE_LABEL): Likewise.
(ASM_OUTPUT_LABELREF): Likewise.
(ASM_OUTPUT_COMMON): Likewise.
(PRINT_OPERAND): Handle 'K', 'W', default.
(PRINT_OPERAND_ADDRESS): New.
(Lots of defines): Add support for TARGET_ELF_ABI.
* i370.md (attr length): New. Define for all patterns.
(*): Lots of tweeks to assembly output and constraints.
Mon Jul 19 15:09:29 1999 David Edelsohn <edelsohn@gnu.org> Mon Jul 19 15:09:29 1999 David Edelsohn <edelsohn@gnu.org>
* rs6000.md (arithmetic, logical, and shift Rc combiner patterns): * rs6000.md (arithmetic, logical, and shift Rc combiner patterns):
......
This directory contains code for building a compiler for the
32-bit ESA/390 architecture. It supports three different styles
of assembly:
-- MVS for use with the HLASM assembler
-- Open Edition (USS Unix System Services)
-- ELF/Linux for use with the binutils/gas GNU assembler.
Cross-compiling Hints
---------------------
When building a cross-compiler on AIX, set the environment variable CC
and be sure to set the -ma and -qcpluscmt flags; i.e.
export CC="cc -ma -qcpluscmt"
do this *before* running configure, e.g.
configure --target=i370-ibm-linux --prefix=/where/to/install/usr
The Objective-C and FORTRAN front ends don't build. To avoid looking at
errors, do only
make LANGUAGES=c
OpenEdition Hints
-----------------
The shell script "install" is handy for users of OpenEdition.
ChangeLog
---------
Oct98-Dec98 -- add ELF back end; work on getting ABI more or less correct.
98.12.05 -- fix numerous MVC bugs
99.02.06 -- multiply insn sometimes not generated when needed.
-- extendsidi bugs, bad literal values printed
-- remove broken adddi subdi patterns
99.02.15 -- add clrstrsi pattern
-- fix -O2 divide bug
99.03.04 -- base & index reg usage bugs
99.03.15 -- fixes for returning long longs and structs (struct value return)
99.03.29 -- fix handling & alignment of shorts
99.03.31 -- clobbered register 14 is not always clobbered
99.04.02 -- operand constraints for cmphi
99.04.07 -- function pointer fixes for call, call_value patterns,
function pointers derefed once too often.
99.04.14 -- add pattern to print double-wide int
-- check intval<4096 for misc operands
-- add clrstrsi pattern
-- movstrsi fixes
99.04.16 -- use r2 to pass args into r11 in subroutine call.
-- fixes to movsi; some operand combinations impossible;
rework constraints
-- start work on forward jump optimization
-- char alignment bug
99.04.25 -- add untyped_call pattern so that builtin_apply works
99.04.27 -- fixes to compare logical under mask
99.04.28 -- reg 2 is clobbered by calls
99.04.30 -- fix rare mulsi bug
99.04.30 -- add constraints so that all RS, SI, SS forms insns have valid
addressing modes
99.04.30 -- major condition code fixes. The old code was just way off
w.r.t. which insns set condition code, and the codes that
were set. The extent of this damage was unbeleivable.
99.05.01 -- restructuring of operand constraints on many patterns,
many lead to invalid instructions being genned.
99.05.02 -- float pt fixes
-- fix movdi issue bugs
99.05.03 -- fix divide insn; was dividing incorrectly
99.05.05 -- fix sign extension problems on andhi
-- deprecate some constraints
99.05.06 -- add set_attr insn lengths; fix misc litpool sizes
-- add notes about how unsigned jumps work (i.e.
arithmetic vs. logical vs. signed vs unsigned).
99.05.11 -- use insn length to predict forward branch target;
use relative branchining where possible,
remove un-needed base register reload.
99.05.15 -- fix movstrsi, clrstrsi, cmpstrsi patterns as per conversation
w/ Richard Henderson
/* Subroutines for insn-output.c for System/370. /* Subroutines for insn-output.c for System/370.
Copyright (C) 1989, 1993, 1995, 1997 Free Software Foundation, Inc. Copyright (C) 1989, 1993, 1995, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se). Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for MVS C/370 by Dave Pitts (dpitts@nyx.cs.du.edu) Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
Hacked for Linux-ELF/390 by Linas Vepstas (linas@linas.org)
This file is part of GNU CC. This file is part of GNU CC.
...@@ -24,7 +25,11 @@ Boston, MA 02111-1307, USA. */ ...@@ -24,7 +25,11 @@ Boston, MA 02111-1307, USA. */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "rtl.h" #include "rtl.h"
#include "tree.h"
#include "regs.h" #include "regs.h"
#include "hard-reg-set.h" #include "hard-reg-set.h"
#include "real.h" #include "real.h"
...@@ -35,26 +40,34 @@ Boston, MA 02111-1307, USA. */ ...@@ -35,26 +40,34 @@ Boston, MA 02111-1307, USA. */
#include "insn-attr.h" #include "insn-attr.h"
#include "flags.h" #include "flags.h"
#include "recog.h" #include "recog.h"
#ifdef sun
#include <sys/types.h>
#include <ctype.h>
#endif
#include <time.h> #include <time.h>
extern FILE *asm_out_file;
/* Label node. This structure is used to keep track of labels
on the various pages in the current routine.
The label_id is the numeric ID of the label,
The label_page is the page on which it actually appears,
The first_ref_page is the page on which the true first ref appears.
The label_addr is an estimate of its location in the current routine,
The label_first & last_ref are estimates of where the earliest and
latest references to this label occur. */
/* Label node, this structure is used to keep track of labels on the
current page. */
typedef struct label_node typedef struct label_node
{ {
struct label_node *label_next; struct label_node *label_next;
int label_id; int label_id;
int label_page; int label_page;
int first_ref_page;
int label_addr;
int label_first_ref;
int label_last_ref;
} }
label_node_t; label_node_t;
/* Is 1 when a label has been generated and the base register must be /* Is 1 when a label has been generated and the base register must be reloaded. */
reloaded. */ int mvs_need_base_reload = 0;
int mvs_label_emitted = 0;
/* Current function starting base page. */ /* Current function starting base page. */
int function_base_page; int function_base_page;
...@@ -83,6 +96,37 @@ static label_node_t *free_anchor = 0; ...@@ -83,6 +96,37 @@ static label_node_t *free_anchor = 0;
/* Assembler source file descriptor. */ /* Assembler source file descriptor. */
static FILE *assembler_source = 0; static FILE *assembler_source = 0;
label_node_t * mvs_get_label ();
/* ===================================================== */
/* defines and functions specific to the HLASM assembler */
#ifdef TARGET_HLASM
#ifndef MAX_MVS_LABEL_SIZE
#define MAX_MVS_LABEL_SIZE 8
#endif
#define MAX_LONG_LABEL_SIZE 255
/* Alias node, this structure is used to keep track of aliases to external
variables. The IBM assembler allows an alias to an external name
that is longer that 8 characters; but only once per assembly.
Also, this structure stores the #pragma map info. */
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;
/* Alias node list anchor. */
static alias_node_t *alias_anchor = 0;
/* Alias number */
static alias_number = 0;
/* Define the length of the internal MVS function table. */ /* Define the length of the internal MVS function table. */
#define MVS_FUNCTION_TABLE_LENGTH 32 #define MVS_FUNCTION_TABLE_LENGTH 32
...@@ -90,16 +134,27 @@ static FILE *assembler_source = 0; ...@@ -90,16 +134,27 @@ static FILE *assembler_source = 0;
and must handled in a special manner. */ and must handled in a special manner. */
static char *mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] = static char *mvs_function_table[MVS_FUNCTION_TABLE_LENGTH] =
{ {
#if defined(HOST_EBCDIC) /* Changed for EBCDIC collating sequence */
"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", "ceil", "edc_acos", "edc_asin", "edc_ata2", "edc_atan", "edc_cos",
"edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10", "edc_cosh", "edc_erf", "edc_erfc", "edc_exp", "edc_gamm", "edc_lg10",
"edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh", "edc_log", "edc_sin", "edc_sinh", "edc_sqrt", "edc_tan", "edc_tanh",
"fabs", "floor", "fmod", "frexp", "hypot", "j0", "fabs", "floor", "fmod", "frexp", "hypot", "j0",
"j1", "jn", "ldexp", "modf", "pow", "y0", "j1", "jn", "ldexp", "modf", "pow", "y0",
"y1", "yn" "y1", "yn"
#endif
}; };
#endif /* TARGET_HLASM */
/* ===================================================== */
/* ASCII to EBCDIC conversion table. */ /* ASCII to EBCDIC conversion table. */
#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
static unsigned char ascebc[256] = static unsigned char ascebc[256] =
{ {
/*00 NL SH SX EX ET NQ AK BL */ /*00 NL SH SX EX ET NQ AK BL */
...@@ -151,10 +206,8 @@ static unsigned char ascebc[256] = ...@@ -151,10 +206,8 @@ static unsigned char ascebc[256] =
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
}; };
#endif
/* EBCDIC to ASCII conversion table. */ /* EBCDIC to ASCII conversion table. */
#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
unsigned char ebcasc[256] = unsigned char ebcasc[256] =
{ {
/*00 NU SH SX EX PF HT LC DL */ /*00 NU SH SX EX PF HT LC DL */
...@@ -222,7 +275,6 @@ unsigned char ebcasc[256] = ...@@ -222,7 +275,6 @@ unsigned char ebcasc[256] =
/*F8 8 9 */ /*F8 8 9 */
0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
}; };
#endif
/* Map characters from one character set to another. /* Map characters from one character set to another.
C is the character to be translated. */ C is the character to be translated. */
...@@ -232,26 +284,278 @@ mvs_map_char (c) ...@@ -232,26 +284,278 @@ mvs_map_char (c)
char c; char c;
{ {
#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC) #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
fprintf (stderr, "mvs_map_char: TE & !HE: c = %02x\n", c);
return ascebc[c]; return ascebc[c];
#else #else
#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC) #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
fprintf (stderr, "mvs_map_char: !TE & HE: c = %02x\n", c);
return ebcasc[c]; return ebcasc[c];
#else #else
fprintf (stderr, "mvs_map_char: !TE & !HE: c = %02x\n", c);
return c; return c;
#endif #endif
#endif #endif
} }
/* ===================================================== */
/* The following three routines are used to determine whther
forward branch is on this page, or is a far jump. We use
the "length" attr on an insn [(set_atter "length" "4")]
to store the largest possible code length that insn
could have. This gives us a hint of the address of a
branch destination, and from that, we can work out
the length of the jump, and whether its on page or not.
*/
/* Return the destination address of a branch. */
int
i370_branch_dest (branch)
rtx branch;
{
rtx dest = SET_SRC (PATTERN (branch));
int dest_uid;
int dest_addr;
/* first, compute the estimated address of the branch target */
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];
/* next, record the address of this insn as the true addr of first ref */
{
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
{
/* avoid bumping into lit pool; use 2x to estimate max possible lits */
base_offset *= 2;
base_offset += mvs_page_code + mvs_page_lit;
}
/* make a conservative estimate of room left on page */
if ((4060 >base_offset) && ( 0 < base_offset)) return 1;
return 0;
}
/* The i370_label_scan() routine is supposed to loop over
all labels and label references in a compilation unit,
and determine whether all label refs appear on the same
code page as the label. If they do, thenm we can avoid
a reload of the base register for that label.
Note that the instruciton addresses used here are only
approximate, and make the sizes of the jumps appear
farther apart then they will actually be. This makes
this code far more conservative than it needed to be.
*/
#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; \
}
void
i370_label_scan (void)
{
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);
/* ??? adjust for tables embedded in the .text section that
* the compiler didn't take into account */
here += tablejump_offset;
insn_addresses[INSN_UID (insn)] = here;
/* check to see if this insn is a label ... */
if (CODE_LABEL == code)
{
int labelno = CODE_LABEL_NUMBER (insn);
lp = mvs_get_label (labelno);
lp -> label_addr = here;
#if 0
/* Supposedly, labels are supposed to have circular
lists of label-refs that reference them,
setup in flow.c, but this does not appear to be the case. */
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);
int labelno;
/* If there is no label for this jump, then this
had better be a ADDR_VEC or an ADDR_DIFF_VEC
and there had better be a vector of labels. */
if (!label)
{
int j;
rtx body = PATTERN (insn);
if (ADDR_VEC == GET_CODE(body))
{
for (j=0; j < XVECLEN (body, 0); j++)
{
int labelno;
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);
}
/* finished with the vector go do next insn */
continue;
}
else
if (ADDR_DIFF_VEC == GET_CODE(body))
{
/* XXX hack alert.
Right now, we leave this as a no-op, but strictly speaking,
this is incorrect. It is possible that a table-jump
driven off of a relative address could take us off-page,
to a place where we need to reload the base reg. So really,
we need to examing both labels, and compare thier values
to the current basereg value.
More generally, this brings up a troubling issue overall:
what happens if a tablejump is split across two pages? I do
not beleive that this case is handled correctly at all, and
can only lead to horrible results if this were to occur.
However, the current situation is not any worse than it was
last week, and so we punt for now.
*/
debug_rtx (insn);
// abort();
for (j=0; j < XVECLEN (body, 0); j++)
{
int labelno;
}
/* finished with the vector go do next insn */
continue;
}
else
{
/* The following appears during make of _eh in libgcc2.a
while not obviously wrong, its weird, so not obviously
right either ...
(jump_insn:HI 125 124 126 (set (pc)
(mem:SI (plus:SI (reg/v:SI 1 r1)
(const_int 4)))) 144 {indirect_jump} (nil)
*/
debug_rtx (insn);
// abort();
continue;
}
}
/* At this point, this jump_insn had better be a plain-old
* ordinary one, grap the label id and go */
if (CODE_LABEL != GET_CODE (label)) abort ();
I370_RECORD_LABEL_REF(label,here);
}
/* Sometimes, we take addresses of labels and use them
as instruction operands ... these show up as REG_NOTES */
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);
}
}
}
}
}
}
/* ===================================================== */
/* Emit reload of base register if indicated. This is to eliminate multiple /* Emit reload of base register if indicated. This is to eliminate multiple
reloads when several labels are generated pointing to the same place reloads when several labels are generated pointing to the same place
in the code. */ in the code.
The page table is written at the end of the function.
The entries in the page table look like
.LPGT0: // PGT0 EQU *
.long .LPG0 // DC A(PG0)
.long .LPG1 // DC A(PG1)
while the prologue generates
L r4,=A(.LPGT0)
Note that this paging scheme breaks down if a single subroutine
has more than about 10MB of code in it ... as long as humans write
code, this shouldn't be a problem ...
*/
int int
check_label_emit (void) check_label_emit (void)
{ {
if (mvs_label_emitted) if (mvs_need_base_reload)
{ {
mvs_label_emitted = 0; mvs_need_base_reload = 0;
mvs_page_code += 4; mvs_page_code += 4;
fprintf (assembler_source, "\tL\t%d,%d(,%d)\n", fprintf (assembler_source, "\tL\t%d,%d(,%d)\n",
BASE_REGISTER, (mvs_page_num - function_base_page) * 4, BASE_REGISTER, (mvs_page_num - function_base_page) * 4,
...@@ -264,12 +568,19 @@ check_label_emit (void) ...@@ -264,12 +568,19 @@ check_label_emit (void)
allocated from memory. allocated from memory.
ID is the label number of the label being added to the list. */ ID is the label number of the label being added to the list. */
int label_node_t *
mvs_add_label (id) mvs_get_label (id)
int id; int id;
{ {
label_node_t *lp; label_node_t *lp;
/* first, lets see if we already go one, if so, use that. */
for (lp = label_anchor; lp; lp = lp->label_next)
{
if (lp->label_id == id) return lp;
}
/* not found, get a new one */
if (free_anchor) if (free_anchor)
{ {
lp = free_anchor; lp = free_anchor;
...@@ -277,21 +588,70 @@ mvs_add_label (id) ...@@ -277,21 +588,70 @@ mvs_add_label (id)
} }
else else
{ {
lp = (label_node_t *) malloc (sizeof (label_node_t)); lp = (label_node_t *) xmalloc (sizeof (label_node_t));
if (lp == 0)
{
fatal ("virtual memory exhausted\n");
abort ();
}
} }
/* initialize for new label */
lp->label_id = id; lp->label_id = id;
lp->label_page = mvs_page_num; lp->label_page = -1;
lp->label_next = label_anchor; 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; 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;
/* OK, we just saw the label. Determine if this label
* needs a reload of the base register */
if ((-1 != lp->first_ref_page) &&
(lp->first_ref_page != mvs_page_num))
{
/* Yep; the first label_ref was on a different page. */
mvs_need_base_reload ++;
return;
}
/* Hmm. Try to see if the estimated address of the last
label_ref is on the current page. If it is, then we
don't need a base reg reload. Note that this estimate
is very conservatively handled; we'll tend to have
a good bit more reloads than actually needed. Someday,
we should tighten the estimates (which are driven by
the (set_att "length") insn attibute.
Currently, we estimate that number of page literals
same as number of insns, which is a vast overestimate,
esp that the estimate of each insn size is its max size. */
/* if latest ref comes before label, we are clear */
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 ++;
} }
/* Check to see if the label is in the list. If 1 is returned then a load /* Check to see if the label is in the list and in the current
and branch on register must be generated. page. If not found, we have to make worst case assumption
that label will be on a different page, and thus will have to
generate a load and branch on register. This is rather
ugly for forward-jumps, but what can we do? For backward
jumps on the same page we can branch directly to address.
ID is the label number of the label being checked. */ ID is the label number of the label being checked. */
int int
...@@ -303,26 +663,54 @@ mvs_check_label (id) ...@@ -303,26 +663,54 @@ mvs_check_label (id)
for (lp = label_anchor; lp; lp = lp->label_next) for (lp = label_anchor; lp; lp = lp->label_next)
{ {
if (lp->label_id == id) if (lp->label_id == id)
{
if (lp->label_page == mvs_page_num)
{
return 1; return 1;
} }
else
{
return 0;
}
}
}
return 0; return 0;
} }
/* Get the page on which the label sits. This will be used to
determine is a register reload is really needed. */
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;
}
/* The label list for the current page freed by linking the list onto the free /* The label list for the current page freed by linking the list onto the free
label element chain. */ label element chain. */
int void
mvs_free_label (void) mvs_free_label_list (void)
{ {
if (label_anchor) if (label_anchor)
{ {
if (free_anchor) label_node_t *last_lp = label_anchor;
label_anchor->label_next = free_anchor; while (last_lp->label_next) last_lp = last_lp->label_next;
last_lp->label_next = free_anchor;
free_anchor = label_anchor; free_anchor = label_anchor;
} }
label_anchor = 0; label_anchor = 0;
} }
/* ====================================================================== */
/* If the page size limit is reached a new code page is started, and the base /* 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, register is set to it. This page break point is counted conservatively,
most literals that have the same value are collapsed by the assembler. most literals that have the same value are collapsed by the assembler.
...@@ -331,6 +719,7 @@ mvs_free_label (void) ...@@ -331,6 +719,7 @@ mvs_free_label (void)
CODE is the length, in bytes, of the instruction to be emitted. CODE is the length, in bytes, of the instruction to be emitted.
LIT is the length of the literal to be emitted. */ LIT is the length of the literal to be emitted. */
#ifdef TARGET_HLASM
int int
mvs_check_page (file, code, lit) mvs_check_page (file, code, lit)
FILE *file; FILE *file;
...@@ -348,10 +737,11 @@ mvs_check_page (file, code, lit) ...@@ -348,10 +737,11 @@ mvs_check_page (file, code, lit)
fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num); fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num);
fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER); fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER);
mvs_page_num++; mvs_page_num++;
fprintf (assembler_source, "\tBALR\t%d,0\n", BASE_REGISTER); /* Safe to use BASR not BALR, since we are
* not switching addressing mode here ... */
fprintf (assembler_source, "\tBASR\t%d,0\n", BASE_REGISTER);
fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num); fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num);
fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER); fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER);
mvs_free_label ();
mvs_page_code = code; mvs_page_code = code;
mvs_page_lit = lit; mvs_page_lit = lit;
return 1; return 1;
...@@ -360,6 +750,53 @@ mvs_check_page (file, code, lit) ...@@ -360,6 +750,53 @@ mvs_check_page (file, code, lit)
mvs_page_lit += lit; mvs_page_lit += lit;
return 0; return 0;
} }
#endif /* TARGET_HLASM */
#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)
{
/* hop past the literal pool */
fprintf (assembler_source, "\tB\t.LPGE%d\n", mvs_page_num);
/* dump the literal pool. The .baligns are optional, since
* ltorg will align to the size of the largest literal
* (which is possibly 8 bytes) */
fprintf (assembler_source, "\t.balign\t4\n");
fprintf (assembler_source, "\t.LTORG\n");
fprintf (assembler_source, "\t.balign\t4\n");
/* we continue execution here ... */
fprintf (assembler_source, ".LPGE%d:\n", mvs_page_num);
fprintf (assembler_source, "\t.DROP\t%d\n", BASE_REGISTER);
mvs_page_num++;
/* BASR puts the contents of the PSW into r3
* that is, r3 will be loaded with the address of "." */
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 /* TARGET_ELF_ABI */
/* ===================================================== */
/* defines and functions specific to the HLASM assembler */
#ifdef TARGET_HLASM
/* Check for C/370 runtime function, they don't use standard calling /* Check for C/370 runtime function, they don't use standard calling
conventions. True is returned if the function is in the table. conventions. True is returned if the function is in the table.
...@@ -389,6 +826,253 @@ mvs_function_check (name) ...@@ -389,6 +826,253 @@ mvs_function_check (name)
} }
/* Add the alias to the current alias list. */
int
mvs_add_alias (realname, aliasname, emitted)
char *realname;
char *aliasname;
int emitted;
{
alias_node_t *ap;
ap = (alias_node_t *) xmalloc (sizeof (alias_node_t));
strcpy (ap->real_name, realname);
strcpy (ap->alias_name, aliasname);
ap->alias_emitted = emitted;
ap->alias_next = alias_anchor;
alias_anchor = ap;
}
/* Check to see if the name needs aliasing */
int
mvs_need_alias (realname)
char *realname;
{
if (mvs_function_check (realname))
return 0;
if (strlen (realname) > MAX_MVS_LABEL_SIZE)
return 1;
if (strchr (realname, '_') != 0)
return 1;
return 0;
}
/* Get the alias from the list.
If 1 is returned then it's in the alias list, 0 if it was not */
int
mvs_get_alias (realname, aliasname)
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))
{
sprintf (aliasname, "ALS%05d", alias_number++);
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;
}
/* Check to see if the alias is in the list.
If 1 is returned then it's in the alias list, 2 it was emitted */
int
mvs_check_alias (realname, aliasname)
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))
{
sprintf (aliasname, "ALS%05d", alias_number++);
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;
}
/* Called from check_newline via the macro HANDLE_PRAGMA.
FINPUT is the source file input stream.
NODE is the tree node for the token after the "pragma".
The result is 1 if the pragma was handled. */
int
handle_pragma (finput, node)
FILE *finput;
tree node;
{
int retval = 0;
register int c;
register char *pname;
if (TREE_CODE (node) != IDENTIFIER_NODE)
return 0;
pname = IDENTIFIER_POINTER (node);
if (strcmp (pname, "map") == 0)
{
char realname[MAX_LONG_LABEL_SIZE + 1];
char aliasname[MAX_MVS_LABEL_SIZE + 1];
char *s;
do {
c = getc (finput);
} while (c == ' ' || c == '\t');
if (c == '(')
{
s = realname;
do {
c = getc (finput);
} while (c == ' ' || c == '\t');
if (c == '\n')
goto PRAGMA_WARNING;
do {
*s++ = c;
c = getc (finput);
} while (isalnum(c) || c == '_');
if (c == '\n')
goto PRAGMA_WARNING;
*s = 0;
if (c == ' ' || c == '\t')
do {
c = getc (finput);
} while (c == ' ' || c == '\t');
if (c == ',')
{
do {
c = getc (finput);
} while (c == ' ' || c == '\t');
if (c == '"')
{
s = aliasname;
c = getc(finput);
do {
if (c == '\\')
{
int d = 0;
do {
c = getc(finput);
if (c >= '0' && c <= '7')
d = (d << 3) | c - '0';
} while (c >= '0' && c <= '7');
ungetc (c, finput);
c = d;
if (d < 1 || d > 255)
warning ("Escape value out of range");
#ifndef HOST_EBCDIC
c = ebcasc[c];
#endif
}
*s++ = c;
c = getc (finput);
if (isspace(c) || c == ')')
goto PRAGMA_WARNING;
} while (c != '"');
*s = 0;
if (strlen (aliasname) > MAX_MVS_LABEL_SIZE)
{
warning ("#pragma map alias is too long, truncated");
aliasname[MAX_MVS_LABEL_SIZE] = '\0';
}
do {
c = getc (finput);
} while (c == ' ' || c == '\t');
if (c == ')')
{
mvs_add_alias (realname, aliasname, 1);
retval = 1;
}
else
goto PRAGMA_WARNING;
}
else
goto PRAGMA_WARNING;
}
else
goto PRAGMA_WARNING;
}
else
{
PRAGMA_WARNING:
warning ("#pragma map options are missing or incorrect");
}
}
return retval;
}
/* defines and functions specific to the HLASM assembler */
#endif /* TARGET_HLASM */
/* ===================================================== */
/* ===================================================== */
/* defines and functions specific to the gas assembler */
#ifdef TARGET_ELF_ABI
/* 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. */
/* no special calling conventions (yet ??) */
int
mvs_function_check (name)
char *name;
{
return 0;
}
#endif /* TARGET_ELF_ABI */
/* ===================================================== */
/* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction. /* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.
OP is the current operation. OP is the current operation.
MODE is the current operation mode. */ MODE is the current operation mode. */
...@@ -460,54 +1144,143 @@ r_or_s_operand (op, mode) ...@@ -460,54 +1144,143 @@ r_or_s_operand (op, mode)
} }
/* Return 1 if the next instruction is an unsigned jump instruction. /* Some remarks about unsigned_jump_follows_p():
INSN is the current instruction. */ gcc is built around the assumption that branches are signed
or unsigned, whereas the 370 doesn't care; its the compares that
are signed or unsigned. Thus, we need to somehow know if we
need to do a signed or an unsigned compare, and we do this by
looking ahead in the instruction sequence until we find a jump.
We then note whether this jump is signed or unsigned, and do the
compare appropriately. Note that we have to scan ahead indefinitley,
as the gcc optimizer may insert any number of instructions between
the compare and the jump.
Note that using conditional branch expanders seems to be be a more
elegant/correct way of doing this. See, for instance, the Alpha
cmpdi and bgt patterns. Note also that for the i370, various
arithmetic insn's set the condition code as well.
The unsigned_jump_follows_p() routine returns a 1 if the next jump
is unsigned. INSN is the current instruction. */
unsigned_jump_follows_p (insn) unsigned_jump_follows_p (insn)
register rtx insn; register rtx insn;
{ {
rtx orig_insn = insn;
while (1)
{
register rtx tmp_insn;
enum rtx_code coda;
insn = NEXT_INSN (insn); insn = NEXT_INSN (insn);
if (GET_CODE (insn) != JUMP_INSN) if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn);
return 0;
insn = XEXP (insn, 3); if (GET_CODE (insn) != JUMP_INSN) continue;
if (GET_CODE (insn) != SET)
return 0;
if (GET_CODE (XEXP (insn, 0)) != PC) tmp_insn = XEXP (insn, 3);
return 0; if (GET_CODE (tmp_insn) != SET) continue;
insn = XEXP (insn, 1); if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue;
if (GET_CODE (insn) != IF_THEN_ELSE)
return 0;
insn = XEXP (insn, 0); tmp_insn = XEXP (tmp_insn, 1);
return GET_CODE (insn) != GE && GET_CODE (insn) != GT if (GET_CODE (tmp_insn) != IF_THEN_ELSE) continue;
&& GET_CODE (insn) != LE && GET_CODE (insn) != LT;
/* if we got to here, this instruction is a jump. Is it signed? */
tmp_insn = XEXP (tmp_insn, 0);
coda = GET_CODE (tmp_insn);
return coda != GE && coda != GT && coda != LE && coda != LT;
}
} }
#ifdef TARGET_HLASM
void void
i370_function_prolog (f, l) i370_function_prolog (f, l)
FILE *f; FILE *f;
int l; int l;
{ {
#if MACROPROLOGUE == 1 #if MACROPROLOGUE == 1
fprintf (f, "* Function %s prologue\n", mvs_function_name);
fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n", fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
STACK_POINTER_OFFSET + l - 120 + STACK_POINTER_OFFSET + l - 120 +
current_function_outgoing_args_size, BASE_REGISTER); 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 */ #else /* MACROPROLOGUE != 1 */
static int function_label_index = 1; static int function_label_index = 1;
static int function_first = 0; static int function_first = 0;
static int function_year, function_month, function_day; static int function_year, function_month, function_day;
static int function_hour, function_minute, function_second; static int function_hour, function_minute, function_second;
int i; int i;
#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, function_second);
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 /* !LE370 */
if (!function_first) if (!function_first)
{ {
struct tm *function_time; struct tm *function_time;
...@@ -530,26 +1303,27 @@ i370_function_prolog (f, l) ...@@ -530,26 +1303,27 @@ i370_function_prolog (f, l)
function_hour, function_minute, function_second); function_hour, function_minute, function_second);
fprintf (f, "\tDC\tCL2'01',CL4'0100'\n"); fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
} }
fprintf (f, "$DSD%03d\tDSECT\n", function_label_index); 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\tD\n");
fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l
+ current_function_outgoing_args_size); + current_function_outgoing_args_size);
fprintf (f, "\tORG\t$DSD%03d\n", function_label_index); fprintf (f, "\tORG\tFDSD%03d\n", function_label_index);
fprintf (f, "\tDS\tCL(120+8)\n"); fprintf (f, "\tDS\tCL(120+8)\n");
fprintf (f, "\tORG\n"); fprintf (f, "\tORG\n");
fprintf (f, "\tDS\t0D\n"); fprintf (f, "\tDS\t0D\n");
fprintf (f, "$DSL%03d\tEQU\t*-$DSD%03d-8\n", function_label_index, fprintf (f, "FDSL%03d\tEQU\t*-FDSD%03d-8\n", function_label_index,
function_label_index); function_label_index);
fprintf (f, "\tDS\t0H\n"); fprintf (f, "\tDS\t0H\n");
assemble_name (f, mvs_function_name); assemble_name (f, mvs_function_name);
fprintf (f, "\tEQU\t*\n"); fprintf (f, "\tCSECT\n");
fprintf (f, "\tUSING\t*,15\n"); fprintf (f, "\tUSING\t*,15\n");
fprintf (f, "\tB\tFPL%03d\n", function_label_index); fprintf (f, "\tB\tFPL%03d\n", function_label_index);
fprintf (f, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index + 1); 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\tX'CE',X'A0',AL1(16)\n");
fprintf (f, "\tDC\tAL4(PPA2)\n"); fprintf (f, "\tDC\tAL4(PPA2)\n");
fprintf (f, "\tDC\tAL4(0)\n"); fprintf (f, "\tDC\tAL4(0)\n");
fprintf (f, "\tDC\tAL4($DSL%03d)\n", function_label_index); fprintf (f, "\tDC\tAL4(FDSL%03d)\n", function_label_index);
fprintf (f, "FPL%03d\tEQU\t*\n", function_label_index + 1); fprintf (f, "FPL%03d\tEQU\t*\n", function_label_index + 1);
fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name), fprintf (f, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
mvs_function_name); mvs_function_name);
...@@ -570,15 +1344,149 @@ i370_function_prolog (f, l) ...@@ -570,15 +1344,149 @@ i370_function_prolog (f, l)
fprintf (f, "\tLR\t13,2\n"); fprintf (f, "\tLR\t13,2\n");
fprintf (f, "\tDROP\t15\n"); fprintf (f, "\tDROP\t15\n");
fprintf (f, "\tBALR\t%d,0\n", BASE_REGISTER); 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, "\tUSING\t*,%d\n", BASE_REGISTER);
function_first = 1;
function_label_index += 2;
#endif /* !LE370 */
#endif /* MACROPROLOGUE */
fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
fprintf (f, "\tLR\t11,1\n"); fprintf (f, "\tLR\t11,1\n");
fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num); fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num);
mvs_page_code = 4; fprintf (f, "* Function %s code\n", mvs_function_name);
mvs_free_label_list ();
mvs_page_code = 6;
mvs_page_lit = 4; mvs_page_lit = 4;
mvs_check_page (f, 0, 0); mvs_check_page (f, 0, 0);
function_base_page = mvs_page_num; function_base_page = mvs_page_num;
/* find all labels in this routine */
i370_label_scan ();
}
#endif /* TARGET_HLASM */
#ifdef TARGET_ELF_ABI
/*
The 370_function_prolog() routine generates the current ELF ABI ES/390 prolog.
It performs the following steps:
-- saves the callers non-volatile registers on the callers stack.
-- computes a new stack top and checks for room for the stack.
-- initializes size and backpointer of new stack frame
-- updates stack pointer to point at new frame.
XXX hack alert -- if the global var int leaf_function is non-zero,
then this is a leaf, and it might be possible to optimize the prologue
into doing even less, e.g. not grabbing a new stackframe or maybe just a
partial stack frame.
XXX hack alert -- the current stack frame is bloated into twice the
needed size by unused entries. These entries make it marginally
compatible with MVS/OE/USS C environment, but really they're not used
and could probably chopped out. Modifications to i370.md would be needed
also, to quite using addresses 136, 140, etc.
*/
void
i370_function_prolog (f, frame_size)
FILE *f;
int frame_size;
{
static int function_label_index = 1;
static int function_first = 0;
int i;
int stackframe_size, soffset, aligned_size;
fprintf (f, "# Function prologue\n");
/* define the stack, put it into its own data segment
FDSE == Function Stack Entry
FDSL == Function Stack Length */
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");
/* Branch to exectuable part of prologue. */
fprintf (f, "\tB\t.LFENT%03d\n", function_label_index);
/* write the length of the stackframe */
fprintf (f, "\t.long\t%d\n", aligned_size);
/* FENT == function prologue entry */
fprintf (f, ".LFENT%03d:\n\t.balign 2\n", /* FENT%03d DS 0H */
function_label_index);
/* store multiple of registers 14,15,0,...12 at 12 bytes from sp */
fprintf (f, "\tSTM\tr14,r12,12(sp)\n");
/* r11 points to arg list in callers stackframe; was passed in r2 */
fprintf (f, "\tLR\tr11,r2\n");
/* r2 == callee stack pointer ; 76(sp) == caller top of stack */
fprintf (f, "\tL\tr2,76(,sp)\n");
/* 4(r15) == callee stack length */
fprintf (f, "\tL\tr0,4(,r15)\n");
/* add callee stack length to caller top of stack */
fprintf (f, "\tALR\tr0,r2\n");
/* is there enough room for this new stack frame? */
fprintf (f, "\tCL\tr0,12(,rtca)\n");
/* if we've got room, skip next 2 insns */
fprintf (f, "\tBNH\t*+10\n");
/* branch to tca to get more stack */
fprintf (f, "\tL\tr15,116(,rtca)\n");
/* go */
fprintf (f, "\tBASR\tr14,r15\n");
/* 72(sp) is something that is propagated up from the base of the stack.
We don't use this anywhere, so we could chop this out. For the moment,
Lets keep it; it might be handy someday ... */
fprintf (f, "\tL\tr15,72(,sp)\n");
/* store the new top-of-stack at 76(callee_stack) */
fprintf (f, "\tSTM\tr15,r0,72(r2)\n");
/* store some PL/1 compatible eyecatcher ???? why bother ??? */
fprintf (f, "\tMVI\t0(r2),0x10\n");
/* store callee stack pointer at 8(sp) */
fprintf (f, "\tST\tr2,8(,sp)\n ");
/* store caller sp at 4(callee_sp) */
fprintf (f, "\tST\tsp,4(,r2)\n ");
/* load calle_sp into sp */
fprintf (f, "\tLR\tsp,r2\n");
fprintf (f, "\t.drop\tr15\n");
/* place contents of the PSW into r3
* that is, place the address of "." into r3 */
fprintf (f, "\tBASR\tr%d,0\n", BASE_REGISTER);
fprintf (f, "\t.using\t.,r%d\n", BASE_REGISTER);
function_first = 1; function_first = 1;
function_label_index += 2; function_label_index ++;
#endif /* MACROPROLOGUE */
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;
/* find all labels in this routine */
i370_label_scan ();
} }
#endif /* TARGET_ELF_ABI */
/* Definitions of target machine for GNU compiler. System/370 version. /* Definitions of target machine for GNU compiler. System/370 version.
Copyright (C) 1989, 1993, 1995, 1996, 1997 Free Software Foundation, Inc. Copyright (C) 1989, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se). Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for C/370 MVS by Dave Pitts (dpitts@nyx.cs.du.edu) Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
Hacked for Linux-ELF/390 by Linas Vepstas (linas@linas.org)
This file is part of GNU CC. This file is part of GNU CC.
...@@ -20,16 +21,8 @@ along with GNU CC; see the file COPYING. If not, write to ...@@ -20,16 +21,8 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330, the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
#define TARGET_VERSION printf (" (370/MVS)"); #ifndef __I370_H__
#define __I370_H__
/* Options for the preprocessor for this target machine. */
#define CPP_SPEC "-trigraphs"
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-DGCC -Dgcc -DMVS -Dmvs -Asystem(mvs) -Acpu(i370) -Amachine(i370)"
/* Run-time compilation parameters selecting different hardware subsets. */ /* Run-time compilation parameters selecting different hardware subsets. */
extern int target_flags; extern int target_flags;
...@@ -42,10 +35,6 @@ extern int mvs_page_code, mvs_page_lit; ...@@ -42,10 +35,6 @@ extern int mvs_page_code, mvs_page_lit;
extern int mvs_page_num, function_base_page; extern int mvs_page_num, function_base_page;
/* True if a label has been emitted. */
extern int mvs_label_emitted;
/* The name of the current function. */ /* The name of the current function. */
extern char *mvs_function_name; extern char *mvs_function_name;
...@@ -76,7 +65,7 @@ extern int current_function_outgoing_args_size; ...@@ -76,7 +65,7 @@ extern int current_function_outgoing_args_size;
#define TARGET_SWITCHES \ #define TARGET_SWITCHES \
{ { "char-instructions", 1, "Generate char instructions"}, \ { { "char-instructions", 1, "Generate char instructions"}, \
{ "no-char-instructions", -1, "Do not generate char instructions"}, \ { "no-char-instructions", -1, "Do not generate char instructions"}, \
{ "", TARGET_DEFAULT, NULL} } { "", TARGET_DEFAULT} }
/* To use IBM supplied macro function prologue and epilogue, define the /* To use IBM supplied macro function prologue and epilogue, define the
following to 1. Should only be needed if IBM changes the definition following to 1. Should only be needed if IBM changes the definition
...@@ -150,20 +139,37 @@ extern int current_function_outgoing_args_size; ...@@ -150,20 +139,37 @@ extern int current_function_outgoing_args_size;
#define TARGET_FLOAT_FORMAT IBM_FLOAT_FORMAT #define TARGET_FLOAT_FORMAT IBM_FLOAT_FORMAT
/* Define character mapping for cross-compiling. */ /* Define character mapping for cross-compiling. */
/* but only define it if really needed, since otherwise it will break builds */
#define TARGET_EBCDIC 1 #ifdef TARGET_EBCDIC
#ifdef HOST_EBCDIC #ifdef HOST_EBCDIC
#define MAP_CHARACTER(c) ((char)(c)) #define MAP_CHARACTER(c) ((char)(c))
#else #else
#define MAP_CHARACTER(c) ((char)mvs_map_char (c)) #define MAP_CHARACTER(c) ((char)mvs_map_char (c))
#endif #endif
#endif
#ifdef TARGET_HLASM
/* Define this macro if you want to implement any pragmas. If defined, it
is a C expression to be executed when #pragma is seen. The
argument FILE is the stdio input stream from which the source
text can be read. CH is the first character after the #pragma. The
result of the expression is the terminating character found
(newline or EOF). */
#define HANDLE_PRAGMA(FILE, NODE) handle_pragma ((FILE), (NODE))
#endif /* TARGET_HLASM */
/* Define maximum length of page minus page escape overhead. */ /* Define maximum length of page minus page escape overhead. */
#define MAX_MVS_PAGE_LENGTH 4080 #define MAX_MVS_PAGE_LENGTH 4080
/* Define if special allocation order desired. */ /* Define special register allocation order desired.
Don't fiddle with this. I did, and I got all sorts of register
spill errors when compiling even relatively simple programs...
I have no clue why ...
E.g. this one is bad:
{ 0, 1, 2, 9, 8, 7, 6, 5, 10, 15, 14, 12, 3, 4, 16, 17, 18, 19, 11, 13 }
*/
#define REG_ALLOC_ORDER \ #define REG_ALLOC_ORDER \
{ 0, 1, 2, 3, 14, 15, 12, 10, 9, 8, 7, 6, 5, 4, 16, 17, 18, 19, 11, 13 } { 0, 1, 2, 3, 14, 15, 12, 10, 9, 8, 7, 6, 5, 4, 16, 17, 18, 19, 11, 13 }
...@@ -186,9 +192,44 @@ extern int current_function_outgoing_args_size; ...@@ -186,9 +192,44 @@ extern int current_function_outgoing_args_size;
#define PAGE_REGISTER 4 #define PAGE_REGISTER 4
/* 1 for registers that have pervasive standard uses and are not available /* 1 for registers that have pervasive standard uses and are not available
for the register allocator. On the 370 under C/370, R13 is stack (DSA) for the register allocator. These are registers that must have fixed,
pointer, R12 is the TCA pointer, R3 is the base register, R4 is the page valid values stored in them for the entire length of the subroutine call,
origin table pointer and R11 is the arg pointer. */ and must not in any way be moved around, jiggered with, etc. That is,
they must never be clobbered, and, if clobbered, the register allocator
will never restore them back.
We use five registers in this special way:
-- R3 which is used as the base register
-- R4 the page origin table pointer used to load R3,
-- R11 the arg pointer.
-- R12 the TCA pointer
-- R13 the stack (DSA) pointer
A fifth register is also exceptional: R14 is used in many branch
instructions to hold the target of the branch. Technically, this
does not qualify R14 as a register with a long-term meaning; it should
be enough, theoretically, to note that these instructions clobber
R14, and let the compiler deal with that. In practice, however,
the "clobber" directive acts as a barrier to optimization, and the
optimizer appears to be unable to perform optimizations around branches.
Thus, a much better strategy appears to give R14 a pervasive use;
this eliminates it from the register pool witout hurting optimization.
There are other registers which have special meanings, but its OK
for them to get clobbered, since other allocator config below will
make sure that they always have the right value. These are for
example:
-- R1 the returned structure pointer.
-- R10 the static chain reg.
-- R15 holds the value a subroutine returns.
Notice that it is *almost* safe to mark R11 as available to the allocator.
By marking it as a call_used_register, in most cases, the compiler
can handle it being clobbered. However, there are a few rare
circumstances where the register allocator will allocate r11 and
also try to use it as the arg pointer ... thus it must be marked fixed.
I think this is a bug, but I can't track it down...
*/
#define FIXED_REGISTERS \ #define FIXED_REGISTERS \
{ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0 } { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0 }
...@@ -199,7 +240,8 @@ extern int current_function_outgoing_args_size; ...@@ -199,7 +240,8 @@ extern int current_function_outgoing_args_size;
saved. saved.
The latter must include the registers where values are returned The latter must include the registers where values are returned
and the register where structure-value addresses are passed. and the register where structure-value addresses are passed.
NOTE: all floating registers are undefined across calls. */ NOTE: all floating registers are undefined across calls.
*/
#define CALL_USED_REGISTERS \ #define CALL_USED_REGISTERS \
{ 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 } { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
...@@ -208,19 +250,25 @@ extern int current_function_outgoing_args_size; ...@@ -208,19 +250,25 @@ extern int current_function_outgoing_args_size;
/* Return number of consecutive hard regs needed starting at reg REGNO /* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE. to hold something of mode MODE.
This is ordinarily the length in words of a value of mode MODE This is ordinarily the length in words of a value of mode MODE
but can be less for certain modes in special long registers. */ but can be less for certain modes in special long registers.
Note that DCmode (complex double) needs two regs.
*/
#define HARD_REGNO_NREGS(REGNO, MODE) \ #define HARD_REGNO_NREGS(REGNO, MODE) \
((REGNO) > 15 ? 1 : (GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) ((REGNO) > 15 ? \
((GET_MODE_SIZE (MODE) + 2*UNITS_PER_WORD - 1) / (2*UNITS_PER_WORD)) : \
(GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD)
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On the 370, the cpu registers can hold QI, HI, SI, SF and DF. The On the 370, the cpu registers can hold QI, HI, SI, SF and DF. The
even registers can hold DI. The floating point registers can hold even registers can hold DI. The floating point registers can hold
either SF or DF. */ either SF, DF, SC or DC. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \ #define HARD_REGNO_MODE_OK(REGNO, MODE) \
((REGNO) < 16 ? ((REGNO) & 1) == 0 || (MODE) != DImode \ ((REGNO) < 16 ? (((REGNO) & 1) == 0 || \
: (MODE) == SFmode || (MODE) == DFmode) (((MODE) != DImode) && ((MODE) != DFmode))) \
: ((MODE) == SFmode || (MODE) == DFmode) || \
(MODE) == SCmode || (MODE) == DCmode)
/* Value is 1 if it is a good idea to tie two pseudo registers when one has /* Value is 1 if it is a good idea to tie two pseudo registers when one has
mode MODE1 and one has mode MODE2. mode MODE1 and one has mode MODE2.
...@@ -263,12 +311,29 @@ extern int current_function_outgoing_args_size; ...@@ -263,12 +311,29 @@ extern int current_function_outgoing_args_size;
#define ARG_POINTER_REGNUM 11 #define ARG_POINTER_REGNUM 11
/* Register in which static-chain is passed to a function. */ /* R10 is register in which static-chain is passed to a function.
Static-chaining is done when a nested function references as a global
a stack variable of its parent: e.g.
int parent_func (int arg) {
int x; // x is in parents stack
void child_func (void) { x++: } // child references x as global var
...
}
*/
#define STATIC_CHAIN_REGNUM 10 #define STATIC_CHAIN_REGNUM 10
/* Register in which address to store a structure value is passed to /* R1 is register in which address to store a structure value is passed to
a function. */ a function. This is used only when returning 64-bit long-long in a 32-bit arch
and when calling functions that return structs by value. e.g.
typedef struct A_s { int a,b,c; } A_t;
A_t fun_returns_value (void) {
A_t a; a.a=1; a.b=2 a.c=3;
return a;
}
In the above, the stroage for the return value is in the callers stack, and
the R1 points at that mem location.
*/
#define STRUCT_VALUE_REGNUM 1 #define STRUCT_VALUE_REGNUM 1
...@@ -347,23 +412,36 @@ enum reg_class ...@@ -347,23 +412,36 @@ enum reg_class
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 #define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1
/* see recog.c for details */
#define EXTRA_CONSTRAINT(OP,C) \
((C) == 'R' ? r_or_s_operand (OP, GET_MODE(OP)) : \
(C) == 'S' ? s_operand (OP, GET_MODE(OP)) : 0) \
/* Given an rtx X being reloaded into a reg required to be in class CLASS, /* Given an rtx X being reloaded into a reg required to be in class CLASS,
return the class of reg to actually use. In general this is just CLASS; return the class of reg to actually use. In general this is just CLASS;
but on some machines in some cases it is preferable to use a more but on some machines in some cases it is preferable to use a more
restrictive class. */ restrictive class.
XXX We reload CONST_INT's into ADDR not DATA regs because on certain
rare occasions when lots of egisters are spilled, reload() will try
to put a const int into r0 and then use r0 as an index register.
*/
#define PREFERRED_RELOAD_CLASS(X, CLASS) \ #define PREFERRED_RELOAD_CLASS(X, CLASS) \
(GET_CODE(X) == CONST_DOUBLE ? FP_REGS : \ (GET_CODE(X) == CONST_DOUBLE ? FP_REGS : \
GET_CODE(X) == CONST_INT ? DATA_REGS : \ GET_CODE(X) == CONST_INT ? (reload_in_progress ? ADDR_REGS : DATA_REGS) : \
GET_CODE(X) == LABEL_REF || \ GET_CODE(X) == LABEL_REF || \
GET_CODE(X) == SYMBOL_REF || \ GET_CODE(X) == SYMBOL_REF || \
GET_CODE(X) == CONST ? ADDR_REGS : (CLASS)) GET_CODE(X) == CONST ? ADDR_REGS : (CLASS))
/* Return the maximum number of consecutive registers needed to represent /* Return the maximum number of consecutive registers needed to represent
mode MODE in a register of class CLASS. */ mode MODE in a register of class CLASS.
Note that DCmode (complex double) needs two regs.
*/
#define CLASS_MAX_NREGS(CLASS, MODE) \ #define CLASS_MAX_NREGS(CLASS, MODE) \
((CLASS) == FP_REGS ? 1 : \ ((CLASS) == FP_REGS ? \
((GET_MODE_SIZE (MODE) + 2*UNITS_PER_WORD - 1) / (2*UNITS_PER_WORD)) : \
(GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Stack layout; function entry, exit and calling. */ /* Stack layout; function entry, exit and calling. */
...@@ -455,18 +533,27 @@ enum reg_class ...@@ -455,18 +533,27 @@ enum reg_class
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
/* Define how to find the value returned by a function. VALTYPE is the /* The FUNCTION_VALUE macro dDefines how to find the value returned by a
data type of the value (as a tree). function. VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL; If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 15. */ otherwise, FUNC is NULL.
#define RET_REG(MODE) ((MODE) == DFmode || (MODE) == SFmode ? 16 : 15) On the 370 the return value is in R15 or R16. However,
DImode (64-bit ints) scalars need to get returned on the stack,
with r15 pointing to the location. To accomplish this, we define
the RETURN_IN_MEMORY macro to be true for both blockmode (structures)
and the DImode scalars.
*/
/* On the 370 the return value is in R15 or R16. */ #define RET_REG(MODE) \
(((MODE) == DCmode || (MODE) == SCmode || (MODE) == TFmode || (MODE) == DFmode || (MODE) == SFmode) ? 16 : 15)
#define FUNCTION_VALUE(VALTYPE, FUNC) \ #define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx(REG, TYPE_MODE (VALTYPE), RET_REG(TYPE_MODE(VALTYPE))) gen_rtx(REG, TYPE_MODE (VALTYPE), RET_REG(TYPE_MODE(VALTYPE)))
#define RETURN_IN_MEMORY(VALTYPE) \
((DImode == TYPE_MODE (VALTYPE)) || (BLKmode == TYPE_MODE (VALTYPE)))
/* Define how to find the value returned by a library function assuming /* Define how to find the value returned by a library function assuming
the value has mode MODE. */ the value has mode MODE. */
...@@ -481,84 +568,6 @@ enum reg_class ...@@ -481,84 +568,6 @@ enum reg_class
#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) #define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
/* This macro generates the assembly code for function entry.
All of the C/370 environment is preserved. */
#define FUNCTION_PROLOGUE(FILE, LSIZE) i370_function_prolog ((FILE), (LSIZE));
#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
{ \
if (strlen (NAME) * 2 > mvs_function_name_length) \
{ \
if (mvs_function_name) \
free (mvs_function_name); \
mvs_function_name = 0; \
} \
if (!mvs_function_name) \
{ \
mvs_function_name_length = strlen (NAME) * 2; \
mvs_function_name = (char *) malloc (mvs_function_name_length); \
if (mvs_function_name == 0) \
{ \
fatal ("virtual memory exceeded"); \
abort (); \
} \
} \
if (!strcmp (NAME, "main")) \
strcpy (mvs_function_name, "gccmain"); \
else \
strcpy (mvs_function_name, NAME); \
}
/* This macro generates the assembly code for function exit, on machines
that need it. If FUNCTION_EPILOGUE is not defined then individual
return instructions are generated for each return statement. Args are
same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
#if MACROEPILOGUE == 1
#define FUNCTION_EPILOGUE(FILE, LSIZE) \
{ \
int i; \
check_label_emit(); \
mvs_check_page (FILE,14,0); \
fprintf (FILE, "\tEDCEPIL\n"); \
mvs_page_num++; \
fprintf (FILE, "\tDS\t0F\n" ); \
fprintf (FILE, "\tLTORG\n"); \
fprintf (FILE, "\tDS\t0F\n"); \
fprintf (FILE, "PGT%d\tEQU\t*\n", function_base_page); \
mvs_free_label(); \
for ( i = function_base_page; i < mvs_page_num; i++ ) \
fprintf (FILE, "\tDC\tA(PG%d)\n", i); \
}
#else /* MACROEPILOGUE != 1 */
#define FUNCTION_EPILOGUE(FILE, LSIZE) \
{ \
int i; \
check_label_emit(); \
mvs_check_page (FILE,14,0); \
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("); \
mvs_page_num++; \
assemble_name (FILE, mvs_function_name); \
fprintf (FILE, ")\n" ); \
fprintf (FILE, "\tDS\t0F\n" ); \
fprintf (FILE, "\tLTORG\n"); \
fprintf (FILE, "\tDS\t0F\n"); \
fprintf (FILE, "PGT%d\tEQU\t*\n", function_base_page); \
mvs_free_label(); \
for ( i = function_base_page; i < mvs_page_num; i++ ) \
fprintf (FILE, "\tDC\tA(PG%d)\n", i); \
}
#endif /* MACROEPILOGUE */
/* Output assembler code for a block containing the constant parts of a /* Output assembler code for a block containing the constant parts of a
trampoline, leaving space for the variable parts. trampoline, leaving space for the variable parts.
...@@ -572,15 +581,21 @@ enum reg_class ...@@ -572,15 +581,21 @@ enum reg_class
BR 15 BR 15
X DS 0F X DS 0F
Y DS 0F */ Y DS 0F */
/*
I am confused as to why this emitting raw binary, instead of instructions ...
see for example, rs6000/rs000.c for an example of a different way to
do this ... especially since BASR should probably be substituted for BALR.
*/
#define TRAMPOLINE_TEMPLATE(FILE) \ #define TRAMPOLINE_TEMPLATE(FILE) \
{ \ { \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0x05E0)); \ ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x05E0)); \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0x5800 | STATIC_CHAIN_REGNUM << 4)); \ ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x5800 | \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0xE00A)); \ STATIC_CHAIN_REGNUM << 4)); \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0x58F0)); \ ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0xE00A)); \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0xE00E)); \ ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x58F0)); \
ASM_OUTPUT_SHORT (FILE, GEN_INT (0x07FF)); \ ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0xE00E)); \
ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x07FF)); \
ASM_OUTPUT_SHORT (FILE, const0_rtx); \ ASM_OUTPUT_SHORT (FILE, const0_rtx); \
ASM_OUTPUT_SHORT (FILE, const0_rtx); \ ASM_OUTPUT_SHORT (FILE, const0_rtx); \
ASM_OUTPUT_SHORT (FILE, const0_rtx); \ ASM_OUTPUT_SHORT (FILE, const0_rtx); \
...@@ -599,12 +614,6 @@ enum reg_class ...@@ -599,12 +614,6 @@ enum reg_class
emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 16)), FNADDR); \ emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 16)), FNADDR); \
} }
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "Error: No profiling available.\n")
/* Define EXIT_IGNORE_STACK if, when returning from a function, the stack /* Define EXIT_IGNORE_STACK if, when returning from a function, the stack
pointer does not matter (provided there is a frame pointer). */ pointer does not matter (provided there is a frame pointer). */
...@@ -612,11 +621,11 @@ enum reg_class ...@@ -612,11 +621,11 @@ enum reg_class
/* Addressing modes, and classification of registers for them. */ /* Addressing modes, and classification of registers for them. */
/* #define HAVE_POST_INCREMENT 0 */ /* #define HAVE_POST_INCREMENT */
/* #define HAVE_POST_DECREMENT 0 */ /* #define HAVE_POST_DECREMENT */
/* #define HAVE_PRE_DECREMENT 0 */ /* #define HAVE_PRE_DECREMENT */
/* #define HAVE_PRE_INCREMENT 0 */ /* #define HAVE_PRE_INCREMENT */
/* These assume that REGNO is a hard or pseudo reg number. They give /* These assume that REGNO is a hard or pseudo reg number. They give
nonzero only if REGNO is a hard reg of the suitable class or a pseudo nonzero only if REGNO is a hard reg of the suitable class or a pseudo
...@@ -712,11 +721,14 @@ enum reg_class ...@@ -712,11 +721,14 @@ enum reg_class
that wants to use this address. that wants to use this address.
The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
except for CONSTANT_ADDRESS_P which is actually machine-independent. */ except for CONSTANT_ADDRESS_P which is actually machine-independent.
*/
#define COUNT_REGS(X, REGS, FAIL) \ #define COUNT_REGS(X, REGS, FAIL) \
if (REG_P (X) && REG_OK_FOR_BASE_P (X)) \ if (REG_P (X)) { \
REGS += 1; \ if (REG_OK_FOR_BASE_P (X)) REGS += 1; \
else goto FAIL; \
} \
else if (GET_CODE (X) != CONST_INT || (unsigned) INTVAL (X) >= 4096) \ else if (GET_CODE (X) != CONST_INT || (unsigned) INTVAL (X) >= 4096) \
goto FAIL; goto FAIL;
...@@ -760,9 +772,26 @@ enum reg_class ...@@ -760,9 +772,26 @@ enum reg_class
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
/* Try machine-dependent ways of modifying an illegitimate address /* Macro: LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)
Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address. to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c. */ This macro is used in only one place: `memory_address' in explow.c.
Several comments:
(1) It's not obvious that this macro results in better code
than its omission does. For historical reasons we leave it in.
(2) This macro may be (???) implicated in the accidental promotion
or RS operand to RX operands, which bombs out any RS, SI, SS
instruction that was expecting a simple address. Note that
this occurs fairly rarely ...
(3) There is a bug somewhere that causes either r4 to be spilled,
or causes r0 to be used as a base register. Changeing the macro
below will make the bug move around, but will not make it go away
... Note that this is a rare bug ...
*/
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ #define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
{ \ { \
...@@ -787,11 +816,11 @@ enum reg_class ...@@ -787,11 +816,11 @@ enum reg_class
#define CASE_VECTOR_MODE SImode #define CASE_VECTOR_MODE SImode
/* Define as C expression which evaluates to nonzero if the tablejump /* Define this if the tablejump instruction expects the table to contain
instruction expects the table to contain offsets from the address of the offsets from the address of the table.
table.
Do not define this if the table should contain absolute addresses. */ Do not define this if the table should contain absolute addresses. */
/* #define CASE_VECTOR_PC_RELATIVE 1 */
/* #define CASE_VECTOR_PC_RELATIVE */
/* Specify the tree operation to be used to convert reals to integers. */ /* Specify the tree operation to be used to convert reals to integers. */
...@@ -816,7 +845,7 @@ enum reg_class ...@@ -816,7 +845,7 @@ enum reg_class
/* Define this if zero-extension is slow (more than one real instruction). */ /* Define this if zero-extension is slow (more than one real instruction). */
#define SLOW_ZERO_EXTEND #define SLOW_ZERO_EXTEND 1
/* Nonzero if access to memory by bytes is slow and undesirable. */ /* Nonzero if access to memory by bytes is slow and undesirable. */
...@@ -871,6 +900,18 @@ enum reg_class ...@@ -871,6 +900,18 @@ enum reg_class
case CONST_DOUBLE: \ case CONST_DOUBLE: \
return 4; return 4;
/* A C statement (sans semicolon) to update the integer variable COST
based on the relationship between INSN that is dependent on
DEP_INSN through the dependence LINK. The default is to make no
adjustment to COST. This can be used for example to specify to
the scheduler that an output- or anti-dependence does not incur
the same cost as a data-dependence.
We will want to use this to indicate that there is a cost associated
with the loading, followed by use of base registers ...
#define ADJUST_COST (INSN, LINK, DEP_INSN, COST)
*/
/* Tell final.c how to eliminate redundant test instructions. */ /* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status /* Here we define machine-dependent flags and fields in cc_status
...@@ -883,7 +924,18 @@ enum reg_class ...@@ -883,7 +924,18 @@ enum reg_class
On the 370, load insns do not alter the cc's. However, in some On the 370, load insns do not alter the cc's. However, in some
cases these instructions can make it possibly invalid to use the cases these instructions can make it possibly invalid to use the
saved cc's. In those cases we clear out some or all of the saved saved cc's. In those cases we clear out some or all of the saved
cc's so they won't be used. */ cc's so they won't be used.
Note that only some arith instructions set the CC. These include
add, subtract, complement, various shifts. Note that multiply
and divide do *not* set set the CC. Therefore, in the code below,
don't set the status for MUL, DIV, etc.
Note that the bitwise ops set the condition code, but not in a
way that we can make use of it. So we treat these as clobbering,
rather than setting the CC. These are clobbered in the individual
instruction patterns that use them. Use CC_STATUS_INIT to clobber.
*/
#define NOTICE_UPDATE_CC(EXP, INSN) \ #define NOTICE_UPDATE_CC(EXP, INSN) \
{ \ { \
...@@ -910,11 +962,17 @@ enum reg_class ...@@ -910,11 +962,17 @@ enum reg_class
cc_status.value2 = 0; \ cc_status.value2 = 0; \
switch (GET_CODE (XEXP (exp, 1))) \ switch (GET_CODE (XEXP (exp, 1))) \
{ \ { \
case PLUS: case MINUS: case MULT: /* case UMULT: */ \ case PLUS: case MINUS: case NEG: \
case DIV: case UDIV: case NEG: case ASHIFT: \ case NOT: case ABS: \
case ASHIFTRT: case AND: case IOR: case XOR: \
case ABS: case NOT: \
CC_STATUS_SET (XEXP (exp, 0), XEXP (exp, 1)); \ CC_STATUS_SET (XEXP (exp, 0), XEXP (exp, 1)); \
\
/* mult and div don't set any cc codes !! */ \
case MULT: /* case UMULT: */ case DIV: case UDIV: \
/* and, or and xor set the cc's the wrong way !! */ \
case AND: case IOR: case XOR: \
/* some shifts set the CC some don't. */ \
case ASHIFT: case ASHIFTRT: \
do {} while (0); \
} \ } \
} \ } \
} \ } \
...@@ -934,13 +992,46 @@ enum reg_class ...@@ -934,13 +992,46 @@ enum reg_class
#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ #define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
{ if (cc_status.flags & CC_NO_OVERFLOW) return NO_OV; return NORMAL; } { if (cc_status.flags & CC_NO_OVERFLOW) return NO_OV; return NORMAL; }
/* ------------------------------------------ */
/* Control the assembler format that we output. */ /* Control the assembler format that we output. */
/* Define the parentheses used to group arithmetic operations
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#ifdef TARGET_EBCDIC
#define TARGET_ESC 39
#define TARGET_BELL 47
#define TARGET_BS 22
#define TARGET_TAB 5
#define TARGET_NEWLINE 21
#define TARGET_VT 11
#define TARGET_FF 12
#define TARGET_CR 13
#else
#define TARGET_BELL 007
#define TARGET_BS 010
#define TARGET_TAB 011
#define TARGET_NEWLINE 012
#define TARGET_VT 013
#define TARGET_FF 014
#define TARGET_CR 015
#endif
/* ======================================================== */
#ifdef TARGET_HLASM
#define TEXT_SECTION_ASM_OP "* Program text area" #define TEXT_SECTION_ASM_OP "* Program text area"
#define DATA_SECTION_ASM_OP "* Program data area" #define DATA_SECTION_ASM_OP "* Program data area"
#define INIT_SECTION_ASM_OP "* Program initialization area" #define INIT_SECTION_ASM_OP "* Program initialization area"
#define SHARED_SECTION_ASM_OP "* Program shared data"
#define CTOR_LIST_BEGIN /* NO OP */ #define CTOR_LIST_BEGIN /* NO OP */
#define CTOR_LIST_END /* NO OP */ #define CTOR_LIST_END /* NO OP */
#define MAX_MVS_LABEL_SIZE 8
/* How to refer to registers in assembler output. This sequence is /* How to refer to registers in assembler output. This sequence is
indexed by compiler's hard-register-number (see above). */ indexed by compiler's hard-register-number (see above). */
...@@ -952,10 +1043,12 @@ enum reg_class ...@@ -952,10 +1043,12 @@ enum reg_class
} }
/* How to renumber registers for dbx and gdb. */ /* How to renumber registers for dbx and gdb. */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO) #define DBX_REGISTER_NUMBER(REGNO) (REGNO)
#define ASM_FILE_START(FILE) fputs ("\tCSECT\n", FILE); #define ASM_FILE_START(FILE) \
{ fputs ("\tRMODE\tANY\n", FILE); \
fputs ("\tCSECT\n", FILE); }
#define ASM_FILE_END(FILE) fputs ("\tEND\n", FILE); #define ASM_FILE_END(FILE) fputs ("\tEND\n", FILE);
#define ASM_IDENTIFY_GCC(FILE) #define ASM_IDENTIFY_GCC(FILE)
#define ASM_COMMENT_START "*" #define ASM_COMMENT_START "*"
...@@ -965,26 +1058,36 @@ enum reg_class ...@@ -965,26 +1058,36 @@ enum reg_class
#define ASM_OUTPUT_LABEL(FILE, NAME) \ #define ASM_OUTPUT_LABEL(FILE, NAME) \
{ assemble_name (FILE, NAME); fputs ("\tEQU\t*\n", FILE); } { assemble_name (FILE, NAME); fputs ("\tEQU\t*\n", FILE); }
#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) /* NO OP */ #define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
{ \
char temp[MAX_MVS_LABEL_SIZE + 1]; \
if (mvs_check_alias (NAME, temp) == 2) \
{ \
fprintf (FILE, "%s\tALIAS\tC'%s'\n", temp, NAME); \
} \
}
#define ASM_GLOBALIZE_LABEL(FILE, NAME) \ #define ASM_GLOBALIZE_LABEL(FILE, NAME) \
{ fputs ("\tENTRY\t", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE); } { \
char temp[MAX_MVS_LABEL_SIZE + 1]; \
if (mvs_check_alias (NAME, temp) == 2) \
{ \
fprintf (FILE, "%s\tALIAS\tC'%s'\n", temp, NAME); \
} \
fputs ("\tENTRY\t", FILE); \
assemble_name (FILE, NAME); \
fputs ("\n", FILE); \
}
/* MVS externals are limited to 8 characters, upper case only. /* MVS externals are limited to 8 characters, upper case only.
The '_' is mapped to '@', except for MVS functions, then '#'. */ The '_' is mapped to '@', except for MVS functions, then '#'. */
#define MAX_MVS_LABEL_SIZE 8
#define ASM_OUTPUT_LABELREF(FILE, NAME) \ #define ASM_OUTPUT_LABELREF(FILE, NAME) \
{ \ { \
char *bp, ch, temp[MAX_MVS_LABEL_SIZE + 1]; \ char *bp, ch, temp[MAX_MVS_LABEL_SIZE + 1]; \
if (strlen (NAME) > MAX_MVS_LABEL_SIZE) \ if (!mvs_get_alias (NAME, temp)) \
{ \ strcpy (temp, NAME); \
strncpy (temp, NAME, MAX_MVS_LABEL_SIZE); \
temp[MAX_MVS_LABEL_SIZE] = '\0'; \
} \
else \
strcpy (temp,NAME); \
if (!strcmp (temp,"main")) \ if (!strcmp (temp,"main")) \
strcpy (temp,"gccmain"); \ strcpy (temp,"gccmain"); \
if (mvs_function_check (temp)) \ if (mvs_function_check (temp)) \
...@@ -994,7 +1097,7 @@ enum reg_class ...@@ -994,7 +1097,7 @@ enum reg_class
for (bp = temp; *bp; bp++) \ for (bp = temp; *bp; bp++) \
{ \ { \
if (islower (*bp)) *bp = toupper (*bp); \ if (islower (*bp)) *bp = toupper (*bp); \
if (*bp == '_') *bp = ch; \ else if (*bp == '_') *bp = ch; \
} \ } \
fprintf (FILE, "%s", temp); \ fprintf (FILE, "%s", temp); \
} }
...@@ -1010,12 +1113,13 @@ enum reg_class ...@@ -1010,12 +1113,13 @@ enum reg_class
if (!strcmp (PREFIX,"L")) \ if (!strcmp (PREFIX,"L")) \
{ \ { \
mvs_add_label(NUM); \ mvs_add_label(NUM); \
mvs_label_emitted = 1; \
} \ } \
fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM); \ fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM); \
} }
/* Generate case label. */ /* Generate case label. */
/* hack alert -- I don't get it ... what if its a really big case label?
* wouldn't we have to say label_emitted also ?? */
#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \ #define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \
fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM) fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM)
...@@ -1033,11 +1137,15 @@ enum reg_class ...@@ -1033,11 +1137,15 @@ enum reg_class
fprintf (FILE, "\tDC\tA(L%d-L%d)\n", VALUE, REL) fprintf (FILE, "\tDC\tA(L%d-L%d)\n", VALUE, REL)
/* This is how to output an insn to push a register on the stack. /* This is how to output an insn to push a register on the stack.
It need not be very fast code. */ It need not be very fast code.
Right now, PUSH & POP are used only when profiling is enabled,
and then, only to push the static chain reg and the function struct
value reg, and only if those are used. Since profiling is not
supported anyway, punt on this. */
#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \ #define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \
mvs_check_page (FILE, 8, 4); \ mvs_check_page (FILE, 8, 4); \
fprintf (FILE, "\tS\t13,=F'4'\n\tST\t%s,%d(13)\n", \ fprintf (FILE, "\tSXXX\t13,=F'4'\n\tST\t%s,%d(13)\n", \
reg_names[REGNO], STACK_POINTER_OFFSET) reg_names[REGNO], STACK_POINTER_OFFSET)
/* This is how to output an insn to pop a register from the stack. /* This is how to output an insn to pop a register from the stack.
...@@ -1045,16 +1153,18 @@ enum reg_class ...@@ -1045,16 +1153,18 @@ enum reg_class
#define ASM_OUTPUT_REG_POP(FILE, REGNO) \ #define ASM_OUTPUT_REG_POP(FILE, REGNO) \
mvs_check_page (FILE, 8, 0); \ mvs_check_page (FILE, 8, 0); \
fprintf (FILE, "\tL\t%s,%d(13)\n\tLA\t13,4(13)\n", \ fprintf (FILE, "\tL\t%s,%d(13)\n\tLAXXX\t13,4(13)\n", \
reg_names[REGNO], STACK_POINTER_OFFSET) reg_names[REGNO], STACK_POINTER_OFFSET)
/* TBD: hack alert XXX these two float point macros print horribly
incorrect things when run in cross-compiler mode. Thats's because
in cross-compiler mode, the VALUE is not really a double. See below,
in the ELF section, for the correct implementation. */
/* This is how to output an assembler line defining a `double' constant. */ /* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \ #define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
fprintf (FILE, "\tDC\tD'%.18G'\n", (VALUE)) fprintf (FILE, "\tDC\tD'%.18G'\n", (VALUE))
/* This is how to output an assembler line defining a `float' constant. */ /* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE, VALUE) \ #define ASM_OUTPUT_FLOAT(FILE, VALUE) \
fprintf (FILE, "\tDC\tE'%.9G'\n", (VALUE)) fprintf (FILE, "\tDC\tE'%.9G'\n", (VALUE))
...@@ -1169,6 +1279,11 @@ enum reg_class ...@@ -1169,6 +1279,11 @@ enum reg_class
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ #define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
{ \ { \
char temp[MAX_MVS_LABEL_SIZE + 1]; \
if (mvs_check_alias(NAME, temp) == 2) \
{ \
fprintf (FILE, "%s\tALIAS\tC'%s'\n", temp, NAME); \
} \
fputs ("\tENTRY\t", FILE); \ fputs ("\tENTRY\t", FILE); \
assemble_name (FILE, NAME); \ assemble_name (FILE, NAME); \
fputs ("\n", FILE); \ fputs ("\n", FILE); \
...@@ -1199,41 +1314,25 @@ enum reg_class ...@@ -1199,41 +1314,25 @@ enum reg_class
sprintf ((OUTPUT), "%s%d", (NAME), (LABELNO)); \ sprintf ((OUTPUT), "%s%d", (NAME), (LABELNO)); \
} }
/* Define the parentheses used to group arithmetic operations /* Print operand XV (an rtx) in assembler syntax to file FILE.
in assembler code. */
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
/* Define results of standard character escape sequences. */
#define TARGET_BELL 47
#define TARGET_BS 22
#define TARGET_TAB 5
#define TARGET_NEWLINE 21
#define TARGET_VT 11
#define TARGET_FF 12
#define TARGET_CR 13
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and X is null. */ For `%' followed by punctuation, CODE is the punctuation and XV is null. */
#define PRINT_OPERAND(FILE, X, CODE) \ #define PRINT_OPERAND(FILE, XV, CODE) \
{ \ { \
switch (GET_CODE (X)) \ switch (GET_CODE (XV)) \
{ \ { \
static char curreg[4]; \ static char curreg[4]; \
case REG: \ case REG: \
if (CODE == 'N') \ if (CODE == 'N') \
strcpy (curreg, reg_names[REGNO (X) + 1]); \ strcpy (curreg, reg_names[REGNO (XV) + 1]); \
else \ else \
strcpy (curreg, reg_names[REGNO (X)]); \ strcpy (curreg, reg_names[REGNO (XV)]); \
fprintf (FILE, "%s", curreg); \ fprintf (FILE, "%s", curreg); \
break; \ break; \
case MEM: \ case MEM: \
{ \ { \
rtx addr = XEXP (X, 0); \ rtx addr = XEXP (XV, 0); \
if (CODE == 'O') \ if (CODE == 'O') \
{ \ { \
if (GET_CODE (addr) == PLUS) \ if (GET_CODE (addr) == PLUS) \
...@@ -1249,61 +1348,81 @@ enum reg_class ...@@ -1249,61 +1348,81 @@ enum reg_class
fprintf (FILE, "%s", reg_names[REGNO (addr)]); \ fprintf (FILE, "%s", reg_names[REGNO (addr)]); \
} \ } \
else \ else \
output_address (XEXP (X, 0)); \ output_address (XEXP (XV, 0)); \
} \ } \
break; \ break; \
case SYMBOL_REF: \ case SYMBOL_REF: \
case LABEL_REF: \ case LABEL_REF: \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
if (SYMBOL_REF_FLAG (X)) fprintf (FILE, "=V("); \ if (SYMBOL_REF_FLAG (XV)) fprintf (FILE, "=V("); \
else fprintf (FILE, "=A("); \ else fprintf (FILE, "=A("); \
output_addr_const (FILE, X); \ output_addr_const (FILE, XV); \
fprintf (FILE, ")"); \ fprintf (FILE, ")"); \
break; \ break; \
case CONST_INT: \ case CONST_INT: \
if (CODE == 'B') \ if (CODE == 'B') \
fprintf (FILE, "%d", INTVAL (X) & 0xff); \ fprintf (FILE, "%d", INTVAL (XV) & 0xff); \
else if (CODE == 'X') \ else if (CODE == 'X') \
fprintf (FILE, "%02X", INTVAL (X) & 0xff); \ fprintf (FILE, "%02X", INTVAL (XV) & 0xff); \
else if (CODE == 'h') \ else if (CODE == 'h') \
fprintf (FILE, "%d", (INTVAL (X) << 16) >> 16); \ fprintf (FILE, "%d", (INTVAL (XV) << 16) >> 16); \
else if (CODE == 'H') \ else if (CODE == 'H') \
{ \ { \
mvs_page_lit += 2; \ mvs_page_lit += 2; \
fprintf (FILE, "=H'%d'", (INTVAL (X) << 16) >> 16); \ fprintf (FILE, "=H'%d'", (INTVAL (XV) << 16) >> 16); \
} \
else if (CODE == 'K') \
{ \
/* auto sign-extension of signed 16-bit to signed 32-bit */ \
mvs_page_lit += 4; \
fprintf (FILE, "=F'%d'", (INTVAL (XV) << 16) >> 16); \
} \
else if (CODE == 'W') \
{ \
/* hand-built sign-extension of signed 32-bit to 64-bit */ \
mvs_page_lit += 8; \
if (0 <= INTVAL (XV)) { \
fprintf (FILE, "=XL8'00000000"); \
} else { \
fprintf (FILE, "=XL8'FFFFFFFF"); \
} \
fprintf (FILE, "%08X'", INTVAL (XV)); \
} \ } \
else \ else \
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
fprintf (FILE, "=F'%d'", INTVAL (X)); \ fprintf (FILE, "=F'%d'", INTVAL (XV)); \
} \ } \
break; \ break; \
case CONST_DOUBLE: \ case CONST_DOUBLE: \
if (GET_MODE (X) == DImode) \ if (GET_MODE (XV) == DImode) \
{ \ { \
if (CODE == 'M') \ if (CODE == 'M') \
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_LOW (X)); \ fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_LOW (XV)); \
} \ } \
else if (CODE == 'L') \ else if (CODE == 'L') \
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_HIGH (X)); \ fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_HIGH (XV)); \
} \ } \
else \ else \
{ \ { \
mvs_page_lit += 8; \ mvs_page_lit += 8; \
fprintf (FILE, "=XL8'%08X%08X'", CONST_DOUBLE_LOW (X), \ fprintf (FILE, "=XL8'%08X%08X'", CONST_DOUBLE_LOW (XV), \
CONST_DOUBLE_HIGH (X)); \ CONST_DOUBLE_HIGH (XV)); \
} \ } \
} \ } \
else \ else \
{ \ { \
/* hack alert -- this prints wildly incorrect values */ \
/* when run in cross-compiler mode. See ELF section */ \
/* for suggested fix */ \
union { double d; int i[2]; } u; \ union { double d; int i[2]; } u; \
u.i[0] = CONST_DOUBLE_LOW (X); \ u.i[0] = CONST_DOUBLE_LOW (XV); \
u.i[1] = CONST_DOUBLE_HIGH (X); \ u.i[1] = CONST_DOUBLE_HIGH (XV); \
if (GET_MODE (X) == SFmode) \ if (GET_MODE (XV) == SFmode) \
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
fprintf (FILE, "=E'%.9G'", u.d); \ fprintf (FILE, "=E'%.9G'", u.d); \
...@@ -1316,22 +1435,22 @@ enum reg_class ...@@ -1316,22 +1435,22 @@ enum reg_class
} \ } \
break; \ break; \
case CONST: \ case CONST: \
if (GET_CODE (XEXP (X, 0)) == PLUS \ if (GET_CODE (XEXP (XV, 0)) == PLUS \
&& GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF) \ && GET_CODE (XEXP (XEXP (XV, 0), 0)) == SYMBOL_REF) \
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
if (SYMBOL_REF_FLAG (XEXP (XEXP (X, 0), 0))) \ if (SYMBOL_REF_FLAG (XEXP (XEXP (XV, 0), 0))) \
{ \ { \
fprintf (FILE, "=V("); \ fprintf (FILE, "=V("); \
ASM_OUTPUT_LABELREF (FILE, \ ASM_OUTPUT_LABELREF (FILE, \
XSTR (XEXP (XEXP (X, 0), 0), 0)); \ XSTR (XEXP (XEXP (XV, 0), 0), 0)); \
fprintf (FILE, ")\n\tA\t%s,=F'%d'", curreg, \ fprintf (FILE, ")\n\tA\t%s,=F'%d'", curreg, \
INTVAL (XEXP (XEXP (X, 0), 1))); \ INTVAL (XEXP (XEXP (XV, 0), 1))); \
} \ } \
else \ else \
{ \ { \
fprintf (FILE, "=A("); \ fprintf (FILE, "=A("); \
output_addr_const (FILE, X); \ output_addr_const (FILE, XV); \
fprintf (FILE, ")"); \ fprintf (FILE, ")"); \
} \ } \
} \ } \
...@@ -1339,7 +1458,7 @@ enum reg_class ...@@ -1339,7 +1458,7 @@ enum reg_class
{ \ { \
mvs_page_lit += 4; \ mvs_page_lit += 4; \
fprintf (FILE, "=F'"); \ fprintf (FILE, "=F'"); \
output_addr_const (FILE, X); \ output_addr_const (FILE, XV); \
fprintf (FILE, "'"); \ fprintf (FILE, "'"); \
} \ } \
break; \ break; \
...@@ -1438,3 +1557,578 @@ enum reg_class ...@@ -1438,3 +1557,578 @@ enum reg_class
break; \ break; \
} \ } \
} }
/* This macro generates the assembly code for function entry.
All of the C/370 environment is preserved. */
#define FUNCTION_PROLOGUE(FILE, LSIZE) i370_function_prolog ((FILE), (LSIZE));
#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
{ \
if (strlen (NAME) * 2 > mvs_function_name_length) \
{ \
if (mvs_function_name) \
free (mvs_function_name); \
mvs_function_name = 0; \
} \
if (!mvs_function_name) \
{ \
mvs_function_name_length = strlen (NAME) * 2; \
mvs_function_name = (char *) malloc (mvs_function_name_length); \
if (mvs_function_name == 0) \
{ \
fatal ("virtual memory exceeded"); \
abort (); \
} \
} \
if (!strcmp (NAME, "main")) \
strcpy (mvs_function_name, "gccmain"); \
else \
strcpy (mvs_function_name, NAME); \
fprintf (FILE, "\tDS\t0F\n"); \
assemble_name (FILE, mvs_function_name); \
fputs ("\tRMODE\tANY\n", FILE); \
assemble_name (FILE, mvs_function_name); \
fputs ("\tCSECT\n", FILE); \
}
/* This macro generates the assembly code for function exit, on machines
that need it. If FUNCTION_EPILOGUE is not defined then individual
return instructions are generated for each return statement. Args are
same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
#if MACROEPILOGUE == 1
#define FUNCTION_EPILOGUE(FILE, LSIZE) \
{ \
int i; \
check_label_emit(); \
mvs_check_page (FILE,14,0); \
fprintf (FILE, "* Function %s epilogue\n", mvs_function_name); \
fprintf (FILE, "\tEDCEPIL\n"); \
mvs_page_num++; \
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); \
}
#else /* MACROEPILOGUE != 1 */
#define FUNCTION_EPILOGUE(FILE, LSIZE) \
{ \
int i; \
check_label_emit(); \
mvs_check_page (FILE,14,0); \
fprintf (FILE, "* Function %s epilogue\n", mvs_function_name); \
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("); \
mvs_page_num++; \
assemble_name (FILE, mvs_function_name); \
fprintf (FILE, ")\n" ); \
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); \
}
#endif /* MACROEPILOGUE */
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
fprintf (FILE, "Error: No profiling available.\n")
#endif /* TARGET_HLASM */
/* ======================================================== */
#ifdef TARGET_ELF_ABI
/* How to refer to registers in assembler output. This sequence is
indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
"f0", "f2", "f4", "f6" \
}
/* How to renumber registers for dbx and gdb. */
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
/* Print operand XV (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
For `%' followed by punctuation, CODE is the punctuation and XV is null. */
#define PRINT_OPERAND(FILE, XV, CODE) \
{ \
switch (GET_CODE (XV)) \
{ \
static char curreg[4]; \
case REG: \
if (CODE == 'N') \
strcpy (curreg, reg_names[REGNO (XV) + 1]); \
else \
strcpy (curreg, reg_names[REGNO (XV)]); \
fprintf (FILE, "%s", curreg); \
break; \
case MEM: \
{ \
rtx addr = XEXP (XV, 0); \
if (CODE == 'O') \
{ \
if (GET_CODE (addr) == PLUS) \
fprintf (FILE, "%d", INTVAL (XEXP (addr, 1))); \
else \
fprintf (FILE, "0"); \
} \
else if (CODE == 'R') \
{ \
if (GET_CODE (addr) == PLUS) \
fprintf (FILE, "%s", reg_names[REGNO (XEXP (addr, 0))]);\
else \
fprintf (FILE, "%s", reg_names[REGNO (addr)]); \
} \
else \
output_address (XEXP (XV, 0)); \
} \
break; \
case SYMBOL_REF: \
case LABEL_REF: \
mvs_page_lit += 4; \
if (SYMBOL_REF_FLAG (XV)) fprintf (FILE, "=V("); \
else fprintf (FILE, "=A("); \
output_addr_const (FILE, XV); \
fprintf (FILE, ")"); \
break; \
case CONST_INT: \
if (CODE == 'B') \
fprintf (FILE, "%d", INTVAL (XV) & 0xff); \
else if (CODE == 'X') \
fprintf (FILE, "%02X", INTVAL (XV) & 0xff); \
else if (CODE == 'h') \
fprintf (FILE, "%d", (INTVAL (XV) << 16) >> 16); \
else if (CODE == 'H') \
{ \
mvs_page_lit += 2; \
fprintf (FILE, "=H'%d'", (INTVAL (XV) << 16) >> 16); \
} \
else if (CODE == 'K') \
{ \
/* auto sign-extension of signed 16-bit to signed 32-bit */ \
mvs_page_lit += 4; \
fprintf (FILE, "=F'%d'", (INTVAL (XV) << 16) >> 16); \
} \
else if (CODE == 'W') \
{ \
/* hand-built sign-extension of signed 32-bit to 64-bit */ \
mvs_page_lit += 8; \
if (0 <= INTVAL (XV)) { \
fprintf (FILE, "=XL8'00000000"); \
} else { \
fprintf (FILE, "=XL8'FFFFFFFF"); \
} \
fprintf (FILE, "%08X'", INTVAL (XV)); \
} \
else \
{ \
mvs_page_lit += 4; \
fprintf (FILE, "=F'%d'", INTVAL (XV)); \
} \
break; \
case CONST_DOUBLE: \
if (GET_MODE (XV) == DImode) \
{ \
if (CODE == 'M') \
{ \
mvs_page_lit += 4; \
fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_LOW (XV)); \
} \
else if (CODE == 'L') \
{ \
mvs_page_lit += 4; \
fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_HIGH (XV)); \
} \
else \
{ \
mvs_page_lit += 8; \
fprintf (FILE, "=yyyyXL8'%08X%08X'", \
CONST_DOUBLE_HIGH (XV), CONST_DOUBLE_LOW (XV)); \
} \
} \
else \
{ \
char buf[50]; \
REAL_VALUE_TYPE rval; \
REAL_VALUE_FROM_CONST_DOUBLE(rval, XV); \
REAL_VALUE_TO_DECIMAL (rval, HOST_WIDE_INT_PRINT_DEC, buf); \
if (GET_MODE (XV) == SFmode) \
{ \
mvs_page_lit += 4; \
fprintf (FILE, "=E'%s'", buf); \
} \
else \
if (GET_MODE (XV) == DFmode) \
{ \
mvs_page_lit += 8; \
fprintf (FILE, "=D'%s'", buf); \
} \
else /* VOIDmode !?!? strange but true ... */ \
{ \
mvs_page_lit += 8; \
fprintf (FILE, "=XL8'%08X%08X'", \
CONST_DOUBLE_HIGH (XV), CONST_DOUBLE_LOW (XV)); \
} \
} \
break; \
case CONST: \
if (GET_CODE (XEXP (XV, 0)) == PLUS \
&& GET_CODE (XEXP (XEXP (XV, 0), 0)) == SYMBOL_REF) \
{ \
mvs_page_lit += 4; \
if (SYMBOL_REF_FLAG (XEXP (XEXP (XV, 0), 0))) \
{ \
fprintf (FILE, "=V("); \
ASM_OUTPUT_LABELREF (FILE, \
XSTR (XEXP (XEXP (XV, 0), 0), 0)); \
fprintf (FILE, ")\n\tA\t%s,=F'%d'", curreg, \
INTVAL (XEXP (XEXP (XV, 0), 1))); \
} \
else \
{ \
fprintf (FILE, "=A("); \
output_addr_const (FILE, XV); \
fprintf (FILE, ")"); \
} \
} \
else \
{ \
mvs_page_lit += 4; \
fprintf (FILE, "=bogus_bad_F'"); \
output_addr_const (FILE, XV); \
fprintf (FILE, "'"); \
/* XXX hack alert this gets gen'd in -fPIC code in relation to a tablejump */ \
/* but its somehow fundamentally broken, I can't make any sense out of it */ \
debug_rtx (XV); \
abort(); \
} \
break; \
default: \
abort(); \
} \
}
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ \
rtx breg, xreg, offset, plus; \
\
switch (GET_CODE (ADDR)) \
{ \
case REG: \
fprintf (FILE, "0(%s)", reg_names[REGNO (ADDR)]); \
break; \
case PLUS: \
breg = 0; \
xreg = 0; \
offset = 0; \
if (GET_CODE (XEXP (ADDR, 0)) == PLUS) \
{ \
if (GET_CODE (XEXP (ADDR, 1)) == REG) \
breg = XEXP (ADDR, 1); \
else \
offset = XEXP (ADDR, 1); \
plus = XEXP (ADDR, 0); \
} \
else \
{ \
if (GET_CODE (XEXP (ADDR, 0)) == REG) \
breg = XEXP (ADDR, 0); \
else \
offset = XEXP (ADDR, 0); \
plus = XEXP (ADDR, 1); \
} \
if (GET_CODE (plus) == PLUS) \
{ \
if (GET_CODE (XEXP (plus, 0)) == REG) \
{ \
if (breg) \
xreg = XEXP (plus, 0); \
else \
breg = XEXP (plus, 0); \
} \
else \
{ \
offset = XEXP (plus, 0); \
} \
if (GET_CODE (XEXP (plus, 1)) == REG) \
{ \
if (breg) \
xreg = XEXP (plus, 1); \
else \
breg = XEXP (plus, 1); \
} \
else \
{ \
offset = XEXP (plus, 1); \
} \
} \
else if (GET_CODE (plus) == REG) \
{ \
if (breg) \
xreg = plus; \
else \
breg = plus; \
} \
else \
{ \
offset = plus; \
} \
if (offset) \
{ \
if (GET_CODE (offset) == LABEL_REF) \
fprintf (FILE, "L%d", \
CODE_LABEL_NUMBER (XEXP (offset, 0))); \
else \
output_addr_const (FILE, offset); \
} \
else \
fprintf (FILE, "0"); \
if (xreg) \
fprintf (FILE, "(%s,%s)", \
reg_names[REGNO (xreg)], reg_names[REGNO (breg)]); \
else \
fprintf (FILE, "(%s)", reg_names[REGNO (breg)]); \
break; \
default: \
mvs_page_lit += 4; \
if (SYMBOL_REF_FLAG (ADDR)) fprintf (FILE, "=V("); \
else fprintf (FILE, "=A("); \
output_addr_const (FILE, ADDR); \
fprintf (FILE, ")"); \
break; \
} \
}
/* This macro generates the assembly code for function exit, on machines
that need it. If FUNCTION_EPILOGUE is not defined then individual
return instructions are generated for each return statement. Args are
same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments
before returning. */
#define FUNCTION_EPILOGUE(FILE, LSIZE) \
{ \
int i; \
check_label_emit(); \
mvs_check_page (FILE,14,0); \
fprintf (FILE, "# Function epilogue\n"); \
fprintf (FILE, "\tL\tsp,4(0,sp)\n"); \
fprintf (FILE, "\tL\tlr,12(0,sp)\n"); \
fprintf (FILE, "\tLM\t2,12,28(sp)\n"); \
fprintf (FILE, "\tBASR\t1,lr\n"); \
mvs_page_num++; \
fprintf (FILE, "# Function literal pool\n"); \
fprintf (FILE, "\t.balign\t4\n"); \
fprintf (FILE, "\t.ltorg\n"); \
fprintf (FILE, "# Function page table\n"); \
fprintf (FILE, "\t.balign\t4\n"); \
fprintf (FILE, ".LPGT%d:\n", function_base_page); \
mvs_free_label_list(); \
for ( i = function_base_page; i < mvs_page_num; i++ ) \
fprintf (FILE, "\t.long\t.LPG%d\n", i); \
}
#define FUNCTION_PROLOGUE(FILE, LSIZE) i370_function_prolog ((FILE), (LSIZE));
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
/* Make it a no-op for now, so we can at least compile glibc */
#define FUNCTION_PROFILER(FILE, LABELNO) { \
mvs_check_page (FILE, 24, 4); \
fprintf (FILE, "\tSTM\tr1,r2,%d(sp)\n", STACK_POINTER_OFFSET-8); \
fprintf (FILE, "\tLA\tr1,1(0,0)\n"); \
fprintf (FILE, "\tL\tr2,=A(.LP%d)\n", LABELNO); \
fprintf (FILE, "\tA\tr1,0(r2)\n"); \
fprintf (FILE, "\tST\tr1,0(r2)\n"); \
fprintf (FILE, "\tLM\tr1,r2,%d(sp)\n", STACK_POINTER_OFFSET-8); \
}
/* Don't bother to output .extern pseudo-ops. They are not needed by
ELF assemblers. */
#undef ASM_OUTPUT_EXTERNAL
#define ASM_DOUBLE "\t.double"
#define ASM_LONG "\t.long"
#define ASM_SHORT "\t.short"
#define ASM_BYTE "\t.byte"
/* Argument to the flt pt. macros is a REAL_VALUE_TYPE which
may or may not be a float/double, depending on whther we
are running in cross-compiler mode. */
/* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE, RVAL) { \
char buf[50]; \
REAL_VALUE_TO_DECIMAL (RVAL, HOST_WIDE_INT_PRINT_DOUBLE_HEX, buf); \
fprintf (FILE, "\tDC\tD'%s'\n", buf); \
}
/* This is how to output an assembler line defining a `float' constant. */
#define ASM_OUTPUT_FLOAT(FILE, RVAL) { \
char buf[50]; \
REAL_VALUE_TO_DECIMAL (RVAL, HOST_WIDE_INT_PRINT_DEC, buf); \
fprintf (FILE, "\tDC\tE'%s'\n", buf); \
}
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_INT(FILE,VALUE) \
( fprintf (FILE, "%s ", ASM_LONG), \
output_addr_const (FILE,(VALUE)), \
putc('\n',FILE))
/* Likewise for `char' and `short' constants. */
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
( fprintf (FILE, "%s ", ASM_SHORT), \
output_addr_const (FILE,(VALUE)), \
putc('\n',FILE))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
( fprintf (FILE, "%s ", ASM_BYTE_OP), \
output_addr_const (FILE, (VALUE)), \
putc ('\n', FILE))
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (VALUE))
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#define ASM_OUTPUT_LABEL(FILE,NAME) \
(assemble_name (FILE, NAME), fputs (":\n", FILE))
/* #define ASM_OUTPUT_LABELREF(FILE, NAME) */ /* use gas -- defaults.h */
/* Generate internal label. Since we can branch here from off page, we
must reload the base register. Note that internal labels are generated
for loops, goto's and case labels. */
#undef ASM_OUTPUT_INTERNAL_LABEL
#define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM) \
{ \
if (!strcmp (PREFIX,"L")) \
{ \
mvs_add_label(NUM); \
} \
fprintf (FILE, ".%s%d:\n", PREFIX, NUM); \
}
/* let config/svr4.h define this ...
* #define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, TABLE)
* fprintf (FILE, "%s%d:\n", PREFIX, NUM)
*/
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
mvs_check_page (FILE, 4, 0); \
fprintf (FILE, "\t.long\t.L%d\n", VALUE)
/* This is how to output an element of a case-vector that is relative. */
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
mvs_check_page (FILE, 4, 0); \
fprintf (FILE, "\t.long\t.L%d-.L%d\n", VALUE, REL)
/* Right now, PUSH & POP are used only when profiling is enabled,
and then, only to push the static chain reg and the function struct
value reg, and only if those are used by the function being profiled.
We don't need this for profiling, so punt. */
#define ASM_OUTPUT_REG_PUSH(FILE, REGNO)
#define ASM_OUTPUT_REG_POP(FILE, REGNO)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
#define JUMP_TABLES_IN_TEXT_SECTION 1
/* Define macro used to output shift-double opcodes when the shift
count is in %cl. Some assemblers require %cl as an argument;
some don't.
GAS requires the %cl argument, so override i386/unix.h. */
#undef SHIFT_DOUBLE_OMITS_COUNT
#define SHIFT_DOUBLE_OMITS_COUNT 0
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
/* Allow #sccs in preprocessor. */
#define SCCS_DIRECTIVE
/* Implicit library calls should use memcpy, not bcopy, etc. */
#define TARGET_MEM_FUNCTIONS
/* Output before read-only data. */
#define TEXT_SECTION_ASM_OP ".text"
/* Output before writable (initialized) data. */
#define DATA_SECTION_ASM_OP ".data"
/* Output before writable (uninitialized) data. */
#define BSS_SECTION_ASM_OP ".bss"
/* In the past there was confusion as to what the argument to .align was
in GAS. For the last several years the rule has been this: for a.out
file formats that argument is LOG, and for all other file formats the
argument is 1<<LOG.
However, GAS now has .p2align and .balign pseudo-ops so to remove any
doubt or guess work, and since this file is used for both a.out and other
file formats, we use one of them. */
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
if ((LOG)!=0) fprintf ((FILE), "\t.balign %d\n", 1<<(LOG))
/* This is how to output a command to make the user-level label named NAME
defined for reference from other files. */
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
(fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE))
/* This says how to output an assembler line
to define a global common symbol. */
#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
( fputs (".comm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
/* This says how to output an assembler line
to define a local common symbol. */
#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
( fputs (".lcomm ", (FILE)), \
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (ROUNDED)))
#endif /* TARGET_ELF_ABI */
#endif /* __I370_H__ */
;;- Machine description for GNU compiler -- System/370 version. ;;- Machine description for GNU compiler -- System/370 version.
;; Copyright (C) 1989, 93, 94, 95, 97, 1999 Free Software Foundation, Inc. ;; Copyright (C) 1989, 93, 94, 95, 1997 Free Software Foundation, Inc.
;; Contributed by Jan Stein (jan@cd.chalmers.se). ;; Contributed by Jan Stein (jan@cd.chalmers.se).
;; Modified for MVS C/370 by Dave Pitts (dpitts@nyx.cs.du.edu) ;; Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
;; Lots of Bug Fixes & Enhancements by Linas Vepstas (linas@linas.org)
;; This file is part of GNU CC. ;; This file is part of GNU CC.
...@@ -20,9 +21,9 @@ ...@@ -20,9 +21,9 @@
;; the Free Software Foundation, 59 Temple Place - Suite 330, ;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA. ;; Boston, MA 02111-1307, USA.
;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code ;; =======================================================================
;;- updates for most instructions. ;; Condition codes for some of the instructions (in particular, for
;; add, sub, shift, abs, etc. are handled with the cpp macro NOTICE_UPDATE_CC
;; ;;
;; Special constraints for 370 machine description: ;; Special constraints for 370 machine description:
;; ;;
...@@ -31,17 +32,37 @@ ...@@ -31,17 +32,37 @@
;; I -- An 8-bit constant (0..255). ;; I -- An 8-bit constant (0..255).
;; J -- A 12-bit constant (0..4095). ;; J -- A 12-bit constant (0..4095).
;; K -- A 16-bit constant (-32768..32767). ;; K -- A 16-bit constant (-32768..32767).
;; R -- a valid S operand in an RS, SI or SS instruction, or register
;; S -- a valid S operand in an RS, SI or SS instruction
;;
;; Note this well:
;; When defining an instruction, e.g. the movsi pattern:
;;
;; (define_insn ""
;; [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm")
;; (match_operand:SI 1 "r_or_s_operand" "diR,dim,*fF"))]
;;
;; The "r_or_s_operand" predicate is used to recognize the instruction;
;; however, it is not further used to enforce a constraint at later stages.
;; Thus, for example, although "r_or_s_operand" bars operands of the form
;; base+index+displacement, such operands can none-the-less show up during
;; post-instruction-recog processing: thus, for example, garbage like
;; MVC 152(4,r13),0(r5,r13) might be generated if both op0 and op1 are
;; mem operands. To avoid this, use the S constraint.
;;
;; ;;
;; Special formats used for outputting 370 instructions. ;; Special formats used for outputting 370 instructions.
;; ;;
;; %B -- Print a constant byte integer. ;; %B -- Print a constant byte integer.
;; %H -- Print a signed 16-bit constant. ;; %H -- Print a signed 16-bit constant.
;; %K -- Print a signed 16-bit constant signed-extended to 32-bits.
;; %L -- Print least significant word of a CONST_DOUBLE. ;; %L -- Print least significant word of a CONST_DOUBLE.
;; %M -- Print most significant word of a CONST_DOUBLE. ;; %M -- Print most significant word of a CONST_DOUBLE.
;; %N -- Print next register (second word of a DImode reg). ;; %N -- Print next register (second word of a DImode reg).
;; %O -- Print the offset of a memory reference (PLUS (REG) (CONST_INT)). ;; %O -- Print the offset of a memory reference (PLUS (REG) (CONST_INT)).
;; %R -- Print the register of a memory reference (PLUS (REG) (CONST_INT)). ;; %R -- Print the register of a memory reference (PLUS (REG) (CONST_INT)).
;; %X -- Print a constant byte integer in hex. ;; %X -- Print a constant byte integer in hex.
;; %W -- Print a signed 32-bit int sign-extended to 64-bits.
;; ;;
;; We have a special constraint for pattern matching. ;; We have a special constraint for pattern matching.
;; ;;
...@@ -68,6 +89,15 @@ ...@@ -68,6 +89,15 @@
;; Some *di patterns have been commented out per advice from RMS, as gcc ;; Some *di patterns have been commented out per advice from RMS, as gcc
;; will generate the right things to do. ;; will generate the right things to do.
;; ;;
;; See the note in i370.h about register 14, clobbering it, and optimization.
;; Basically, using clobber in egcs-1.1.1 will ruin ability to optimize around
;; branches, so don't do it.
;;
;; We use the "length" attirbute to store the max possible code size of an
;; insn. We use this length to estimate the length of forward branches, to
;; determine if they're on page or off.
(define_attr "length" "" (const_int 0))
;; ;;
;;- Test instructions. ;;- Test instructions.
...@@ -86,7 +116,9 @@ ...@@ -86,7 +116,9 @@
check_label_emit (); check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"SRDA %0,0\"; return \"SRDA %0,0\";
}") }"
[(set_attr "length" "4")]
)
; ;
; tstsi instruction pattern(s). ; tstsi instruction pattern(s).
...@@ -101,7 +133,9 @@ ...@@ -101,7 +133,9 @@
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LTR %0,%0\"; return \"LTR %0,%0\";
}") }"
[(set_attr "length" "2")]
)
; ;
; tsthi instruction pattern(s). ; tsthi instruction pattern(s).
...@@ -116,7 +150,9 @@ ...@@ -116,7 +150,9 @@
check_label_emit (); check_label_emit ();
mvs_check_page (0, 4, 2); mvs_check_page (0, 4, 2);
return \"CH %0,=H'0'\"; return \"CH %0,=H'0'\";
}") }"
[(set_attr "length" "4")]
)
; ;
; tstqi instruction pattern(s). ; tstqi instruction pattern(s).
...@@ -131,12 +167,15 @@ ...@@ -131,12 +167,15 @@
check_label_emit (); check_label_emit ();
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
/* an unsigned compare to zero is always zero/not-zero... */
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"N %0,=X'000000FF'\"; return \"N %0,=X'000000FF'\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CLI %0,0\"; return \"CLI %0,0\";
}") }"
[(set_attr "length" "4")]
)
(define_insn "tstqi" (define_insn "tstqi"
[(set (cc0) [(set (cc0)
...@@ -147,12 +186,15 @@ ...@@ -147,12 +186,15 @@
check_label_emit (); check_label_emit ();
if (unsigned_jump_follows_p (insn)) if (unsigned_jump_follows_p (insn))
{ {
/* an unsigned compare to zero is always zero/not-zero... */
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"N %0,=X'000000FF'\"; return \"N %0,=X'000000FF'\";
} }
mvs_check_page (0, 8, 0); mvs_check_page (0, 8, 0);
return \"SLL %0,24\;SRA %0,24\"; return \"SLL %0,24\;SRA %0,24\";
}") }"
[(set_attr "length" "8")]
)
; ;
; tstdf instruction pattern(s). ; tstdf instruction pattern(s).
...@@ -167,7 +209,9 @@ ...@@ -167,7 +209,9 @@
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LTDR %0,%0\"; return \"LTDR %0,%0\";
}") }"
[(set_attr "length" "2")]
)
; ;
; tstsf instruction pattern(s). ; tstsf instruction pattern(s).
...@@ -182,7 +226,9 @@ ...@@ -182,7 +226,9 @@
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LTER %0,%0\"; return \"LTER %0,%0\";
}") }"
[(set_attr "length" "2")]
)
;; ;;
;;- Compare instructions. ;;- Compare instructions.
...@@ -243,16 +289,20 @@ ...@@ -243,16 +289,20 @@
if (unsigned_jump_follows_p (insn)) if (unsigned_jump_follows_p (insn))
return \"CL %0,%1\"; return \"CL %0,%1\";
return \"C %0,%1\"; return \"C %0,%1\";
}") }"
[(set_attr "length" "4")]
)
; ;
; cmphi instruction pattern(s). ; cmphi instruction pattern(s).
; ;
; depricate constraint d because it takes multiple instructions
; and a memeory access ...
(define_insn "cmphi" (define_insn "cmphi"
[(set (cc0) [(set (cc0)
(compare (match_operand:HI 0 "register_operand" "d") (compare (match_operand:HI 0 "register_operand" "d")
(match_operand:HI 1 "general_operand" "")))] (match_operand:HI 1 "general_operand" "???dim")))]
"" ""
"* "*
{ {
...@@ -271,7 +321,9 @@ ...@@ -271,7 +321,9 @@
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CH %0,%1\"; return \"CH %0,%1\";
}") }"
[(set_attr "length" "8")]
)
; ;
; cmpqi instruction pattern(s). ; cmpqi instruction pattern(s).
...@@ -279,8 +331,8 @@ ...@@ -279,8 +331,8 @@
(define_insn "" (define_insn ""
[(set (cc0) [(set (cc0)
(compare (match_operand:QI 0 "r_or_s_operand" "g") (compare (match_operand:QI 0 "r_or_s_operand" "dS")
(match_operand:QI 1 "r_or_s_operand" "g")))] (match_operand:QI 1 "r_or_s_operand" "diS")))]
"unsigned_jump_follows_p (insn)" "unsigned_jump_follows_p (insn)"
"* "*
{ {
...@@ -295,7 +347,7 @@ ...@@ -295,7 +347,7 @@
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
mvs_check_page (0, 4, 1); mvs_check_page (0, 4, 1);
return \"CLM %0,1,=FL1'%B1'\"; return \"CLM %0,1,=X'%X1'\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CLM %0,1,%1\"; return \"CLM %0,1,%1\";
...@@ -306,7 +358,7 @@ ...@@ -306,7 +358,7 @@
if (REG_P (operands[1])) if (REG_P (operands[1]))
{ {
mvs_check_page (0, 4, 1); mvs_check_page (0, 4, 1);
return \"CLM %1,1,=FL1'%B0'\"; return \"CLM %1,1,=X'%X0'\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CLI %1,%B0\"; return \"CLI %1,%B0\";
...@@ -324,7 +376,9 @@ ...@@ -324,7 +376,9 @@
cc_status.flags |= CC_REVERSED; cc_status.flags |= CC_REVERSED;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CLM %1,1,%0\"; return \"CLM %1,1,%0\";
}") }"
[(set_attr "length" "8")]
)
(define_insn "cmpqi" (define_insn "cmpqi"
[(set (cc0) [(set (cc0)
...@@ -336,15 +390,15 @@ ...@@ -336,15 +390,15 @@
check_label_emit (); check_label_emit ();
if (unsigned_jump_follows_p (insn)) if (unsigned_jump_follows_p (insn))
{ {
if (REG_P (operands[1]))
{
mvs_check_page (0, 4, 0);
return \"CLM %0,1,%1\";
}
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
mvs_check_page (0, 4, 1); mvs_check_page (0, 4, 1);
return \"CLM %0,1,=FL1'%B1'\"; return \"CLM %0,1,=X'%X1'\";
}
if (!(REG_P (operands[1])))
{
mvs_check_page (0, 4, 0);
return \"CLM %0,1,%1\";
} }
mvs_check_page (0, 8, 0); mvs_check_page (0, 8, 0);
return \"STC %1,140(,13)\;CLM %0,1,140(13)\"; return \"STC %1,140(,13)\;CLM %0,1,140(13)\";
...@@ -356,7 +410,9 @@ ...@@ -356,7 +410,9 @@
} }
mvs_check_page (0, 12, 0); mvs_check_page (0, 12, 0);
return \"SLL %0,24\;SRA %0,24\;C %0,%1\"; return \"SLL %0,24\;SRA %0,24\;C %0,%1\";
}") }"
[(set_attr "length" "18")]
)
; ;
; cmpdf instruction pattern(s). ; cmpdf instruction pattern(s).
...@@ -383,7 +439,9 @@ ...@@ -383,7 +439,9 @@
cc_status.flags |= CC_REVERSED; cc_status.flags |= CC_REVERSED;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CD %1,%0\"; return \"CD %1,%0\";
}") }"
[(set_attr "length" "4")]
)
; ;
; cmpsf instruction pattern(s). ; cmpsf instruction pattern(s).
...@@ -410,7 +468,9 @@ check_label_emit (); ...@@ -410,7 +468,9 @@ check_label_emit ();
cc_status.flags |= CC_REVERSED; cc_status.flags |= CC_REVERSED;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"CE %1,%0\"; return \"CE %1,%0\";
}") }"
[(set_attr "length" "4")]
)
; ;
; cmpstrsi instruction pattern(s). ; cmpstrsi instruction pattern(s).
...@@ -437,7 +497,7 @@ check_label_emit (); ...@@ -437,7 +497,7 @@ check_label_emit ();
} }
else else
{ {
op1 = gen_rtx (MEM, BLKmode, copy_to_mode_reg (SImode, op1)); op1 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op1));
} }
op2 = XEXP (operands[2], 0); op2 = XEXP (operands[2], 0);
...@@ -450,32 +510,41 @@ check_label_emit (); ...@@ -450,32 +510,41 @@ check_label_emit ();
} }
else else
{ {
op2 = gen_rtx (MEM, BLKmode, copy_to_mode_reg (SImode, op2)); op2 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op2));
} }
if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256) if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
{ {
emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
gen_rtx (SET, VOIDmode, operands[0], gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (COMPARE, VOIDmode, op1, op2)), gen_rtx_COMPARE (VOIDmode, op1, op2)),
gen_rtx (USE, VOIDmode, operands[3])))); gen_rtx_USE (VOIDmode, operands[3]))));
} }
else else
{ {
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg1 = gen_reg_rtx (DImode); rtx reg1 = gen_reg_rtx (DImode);
rtx reg2 = gen_reg_rtx (DImode); rtx reg2 = gen_reg_rtx (DImode);
rtx subreg = gen_rtx (SUBREG, SImode, reg1, 1); rtx result = operands[0];
rtx mem1 = operands[1];
emit_insn (gen_rtx (SET, VOIDmode, subreg, operands[3])); rtx mem2 = operands[2];
emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, reg2, 1), rtx len = operands[3];
subreg)); if (!CONSTANT_P (len))
emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, len = force_reg (SImode, len);
gen_rtx (SET, VOIDmode, operands[0],
gen_rtx (COMPARE, VOIDmode, op1, op2)), /* Load up the address+length pairs. */
gen_rtx (USE, VOIDmode, reg1), emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
gen_rtx (USE, VOIDmode, reg2), emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
gen_rtx (CLOBBER, VOIDmode, reg1), force_operand (XEXP (mem1, 0), NULL_RTX));
gen_rtx (CLOBBER, VOIDmode, reg2)))); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0),
force_operand (XEXP (mem2, 0), NULL_RTX));
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len);
/* Compare! */
emit_insn (gen_cmpstrsi_1 (result, reg1, reg2));
} }
DONE; DONE;
}") }")
...@@ -492,26 +561,31 @@ check_label_emit (); ...@@ -492,26 +561,31 @@ check_label_emit ();
{ {
check_label_emit (); check_label_emit ();
mvs_check_page (0, 22, 0); mvs_check_page (0, 22, 0);
return \"LA %0,1\;CLC %O1(%c3,%R1),%2\;BH *+12\;BL *+6\;SLR %0,%0\;LNR %0,%0\"; return \"LA %0,%1\;CLC %O1(%c3,%R1),%2\;BH *+12\;BL *+6\;SLR %0,%0\;LNR %0,%0\";
}") }"
[(set_attr "length" "22")]
)
; Compare a block that is larger than 255 bytes in length. ; Compare a block that is larger than 255 bytes in length.
(define_insn "" (define_insn "cmpstrsi_1"
[(set (match_operand:SI 0 "register_operand" "d") [(set (match_operand:SI 0 "register_operand" "+d")
(compare (match_operand:BLK 1 "general_operand" "m") (compare
(match_operand:BLK 2 "general_operand" "m"))) (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0))
(use (match_operand:DI 3 "register_operand" "d")) (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "+d") 0))))
(use (match_operand:DI 4 "register_operand" "d")) (use (match_dup 1))
(clobber (match_dup 3)) (use (match_dup 2))
(clobber (match_dup 4))] (clobber (match_dup 1))
(clobber (match_dup 2))]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
mvs_check_page (0, 26, 0); mvs_check_page (0, 18, 0);
return \"LA %3,%1\;LA %4,%2\;LA %0,1\;CLCL %3,%4\;BH *+12\;BL *+6\;SLR %0,%0\;LNR %0,%0\"; return \"LA %0,1(0,0)\;CLCL %1,%2\;BH *+12\;BL *+6\;SLR %0,%0\;LNR %0,%0\";
}") }"
[(set_attr "length" "18")]
)
;; ;;
;;- Move instructions. ;;- Move instructions.
...@@ -522,8 +596,11 @@ check_label_emit (); ...@@ -522,8 +596,11 @@ check_label_emit ();
; ;
(define_insn "" (define_insn ""
[(set (match_operand:DI 0 "r_or_s_operand" "=dm") ;; [(set (match_operand:DI 0 "r_or_s_operand" "=dm")
(match_operand:DI 1 "r_or_s_operand" "dim*fF"))] ;; (match_operand:DI 1 "r_or_s_operand" "dim*fF"))]
[(set (match_operand:DI 0 "r_or_s_operand" "=dS,m")
(match_operand:DI 1 "r_or_s_operand" "diS*fF,d*fF"))]
"TARGET_CHAR_INSTRUCTIONS" "TARGET_CHAR_INSTRUCTIONS"
"* "*
{ {
...@@ -551,7 +628,7 @@ check_label_emit (); ...@@ -551,7 +628,7 @@ check_label_emit ();
{ {
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"SLR %0,%0\;LA %N0,%c1\"; return \"SLR %0,%0\;LA %N0,%c1(0,0)\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
...@@ -573,12 +650,16 @@ check_label_emit (); ...@@ -573,12 +650,16 @@ check_label_emit ();
return \"STM %1,%N1,%0\"; return \"STM %1,%N1,%0\";
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(8,%R0),%1\"; return \"MVC %O0(8,%R0),%W1\";
}") }"
[(set_attr "length" "8")]
)
(define_insn "movdi" (define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=dm") ;; [(set (match_operand:DI 0 "general_operand" "=d,dm")
(match_operand:DI 1 "general_operand" "dim*fF"))] ;; (match_operand:DI 1 "general_operand" "dimF,*fd"))]
[(set (match_operand:DI 0 "general_operand" "=d,dm")
(match_operand:DI 1 "r_or_s_operand" "diSF,*fd"))]
"" ""
"* "*
{ {
...@@ -606,7 +687,7 @@ check_label_emit (); ...@@ -606,7 +687,7 @@ check_label_emit ();
{ {
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"SLR %0,%0\;LA %N0,%c1\"; return \"SLR %0,%0\;LA %N0,%c1(0,0)\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
...@@ -622,17 +703,64 @@ check_label_emit (); ...@@ -622,17 +703,64 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STD %1,%0\"; return \"STD %1,%0\";
} }
mvs_check_page (0, 4, 0); else if (REG_P (operands[1]))
return \"STM %1,%N1,%0\"; {
}") /* hack alert -- for some reason, %N0 doesn't work
* when the mem ref is e.g. 168(r13,r1) ...
* add 4 and pray for the best .. */
mvs_check_page (0, 8, 0);
return \"ST %1,%0\;ST %N1,4+%N0\";
}
/* this is almost certainly not what is desired, let it break ... */
mvs_check_page (0, 8, 0);
return \"xxxST %1,%0\;ST %N1,%N0\";
}"
[(set_attr "length" "8")]
)
;; we have got to provide a movdi alternative that will go from
;; register to memory & back in its full glory. However, we try to
;; discourage its use by listing this alternative last.
;; The problem is that the instructions above only provide
;; S-form style (base + displacement) mem access, while the
;; below provvides the full (base+index+displacement) RX-form.
;; These are rarely needed, but when needed they're needed.
(define_insn ""
[(set (match_operand:DI 0 "general_operand" "=d,???m")
(match_operand:DI 1 "general_operand" "???m,d"))]
""
"*
{
check_label_emit ();
if (REG_P (operands[0]))
{
mvs_check_page (0, 8, 0);
return \"L %0,%1\;L %N0,4+%N1\";
}
else if (REG_P (operands[1]))
{
mvs_check_page (0, 8, 0);
return \"ST %1,%0\;ST %N1,4+%N0\";
}
mvs_check_page (0, 6, 0);
/* should never get here ... */
return \"xxxxxxMVC %O0(8,%R0),%W1\";
}"
[(set_attr "length" "8")]
)
; ;
; movsi instruction pattern(s). ; movsi instruction pattern(s).
; ;
(define_insn "" (define_insn ""
[(set (match_operand:SI 0 "r_or_s_operand" "=dm,dm") ;; [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm")
(match_operand:SI 1 "r_or_s_operand" "dim,*fF"))] ;; (match_operand:SI 1 "r_or_s_operand" "diR,dim,*fF"))]
[(set (match_operand:SI 0 "r_or_s_operand" "=d,dS,dm")
(match_operand:SI 1 "general_operand" "dim,diS,di*fF"))]
"TARGET_CHAR_INSTRUCTIONS" "TARGET_CHAR_INSTRUCTIONS"
"* "*
{ {
...@@ -659,7 +787,7 @@ check_label_emit (); ...@@ -659,7 +787,7 @@ check_label_emit ();
&& (unsigned) INTVAL (operands[1]) < 4096) && (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"L %0,%1\"; return \"L %0,%1\";
...@@ -676,7 +804,9 @@ check_label_emit (); ...@@ -676,7 +804,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(4,%R0),%1\"; return \"MVC %O0(4,%R0),%1\";
}") }"
[(set_attr "length" "8")]
)
(define_insn "movsi" (define_insn "movsi"
[(set (match_operand:SI 0 "general_operand" "=d,dm") [(set (match_operand:SI 0 "general_operand" "=d,dm")
...@@ -707,7 +837,7 @@ check_label_emit (); ...@@ -707,7 +837,7 @@ check_label_emit ();
&& (unsigned) INTVAL (operands[1]) < 4096) && (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"L %0,%1\"; return \"L %0,%1\";
...@@ -719,7 +849,9 @@ check_label_emit (); ...@@ -719,7 +849,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"ST %1,%0\"; return \"ST %1,%0\";
}") }"
[(set_attr "length" "8")]
)
;(define_expand "movsi" ;(define_expand "movsi"
; [(set (match_operand:SI 0 "general_operand" "=d,dm") ; [(set (match_operand:SI 0 "general_operand" "=d,dm")
...@@ -734,7 +866,7 @@ check_label_emit (); ...@@ -734,7 +866,7 @@ check_label_emit ();
; && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SYMBOL_REF ; && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SYMBOL_REF
; && SYMBOL_REF_FLAG (XEXP (XEXP (op0, 0), 0))) ; && SYMBOL_REF_FLAG (XEXP (XEXP (op0, 0), 0)))
; { ; {
; op0 = gen_rtx (MEM, SImode, copy_to_mode_reg (SImode, XEXP (op0, 0))); ; op0 = gen_rtx_MEM (SImode, copy_to_mode_reg (SImode, XEXP (op0, 0)));
; } ; }
; ;
; op1 = operands[1]; ; op1 = operands[1];
...@@ -742,10 +874,10 @@ check_label_emit (); ...@@ -742,10 +874,10 @@ check_label_emit ();
; && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF ; && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF
; && SYMBOL_REF_FLAG (XEXP (XEXP (op1, 0), 0))) ; && SYMBOL_REF_FLAG (XEXP (XEXP (op1, 0), 0)))
; { ; {
; op1 = gen_rtx (MEM, SImode, copy_to_mode_reg (SImode, XEXP (op1, 0))); ; op1 = gen_rtx_MEM (SImode, copy_to_mode_reg (SImode, XEXP (op1, 0)));
; } ; }
; ;
; emit_insn (gen_rtx (SET, VOIDmode, op0, op1)); ; emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
; DONE; ; DONE;
;}") ;}")
...@@ -777,7 +909,7 @@ check_label_emit (); ...@@ -777,7 +909,7 @@ check_label_emit ();
&& (unsigned) INTVAL (operands[1]) < 4096) && (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
...@@ -799,7 +931,9 @@ check_label_emit (); ...@@ -799,7 +931,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(2,%R0),%1\"; return \"MVC %O0(2,%R0),%1\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "movhi" (define_insn "movhi"
[(set (match_operand:HI 0 "general_operand" "=d,m") [(set (match_operand:HI 0 "general_operand" "=d,m")
...@@ -825,7 +959,7 @@ check_label_emit (); ...@@ -825,7 +959,7 @@ check_label_emit ();
&& (unsigned) INTVAL (operands[1]) < 4096) && (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
...@@ -837,7 +971,9 @@ check_label_emit (); ...@@ -837,7 +971,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STH %1,%0\"; return \"STH %1,%0\";
}") }"
[(set_attr "length" "4")]
)
; ;
; movqi instruction pattern(s). ; movqi instruction pattern(s).
...@@ -865,10 +1001,11 @@ check_label_emit (); ...@@ -865,10 +1001,11 @@ check_label_emit ();
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
if (INTVAL (operands[1]) >= 0) if ((INTVAL (operands[1]) >= 0)
&& (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"L %0,=F'%c1'\"; return \"L %0,=F'%c1'\";
...@@ -888,7 +1025,9 @@ check_label_emit (); ...@@ -888,7 +1025,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(1,%R0),%1\"; return \"MVC %O0(1,%R0),%1\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "movqi" (define_insn "movqi"
[(set (match_operand:QI 0 "general_operand" "=d,m") [(set (match_operand:QI 0 "general_operand" "=d,m")
...@@ -912,10 +1051,11 @@ check_label_emit (); ...@@ -912,10 +1051,11 @@ check_label_emit ();
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
if (INTVAL (operands[1]) >= 0) if ((INTVAL (operands[1]) >= 0)
&& (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"L %0,=F'%c1'\"; return \"L %0,=F'%c1'\";
...@@ -925,13 +1065,15 @@ check_label_emit (); ...@@ -925,13 +1065,15 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STC %1,%0\"; return \"STC %1,%0\";
}") }"
[(set_attr "length" "4")]
)
; ;
; movestrictqi instruction pattern(s). ; movstrictqi instruction pattern(s).
; ;
(define_insn "movestrictqi" (define_insn "movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "general_operand" "=d")) [(set (strict_low_part (match_operand:QI 0 "general_operand" "=d"))
(match_operand:QI 1 "general_operand" "g"))] (match_operand:QI 1 "general_operand" "g"))]
"" ""
...@@ -945,7 +1087,9 @@ check_label_emit (); ...@@ -945,7 +1087,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"IC %0,%1\"; return \"IC %0,%1\";
}") }"
[(set_attr "length" "8")]
)
; ;
; movstricthi instruction pattern(s). ; movstricthi instruction pattern(s).
...@@ -970,9 +1114,11 @@ check_label_emit (); ...@@ -970,9 +1114,11 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"ICM %0,3,%1\"; return \"ICM %0,3,%1\";
}") }"
[(set_attr "length" "8")]
)
(define_insn "movestricthi" (define_insn "movstricthi"
[(set (strict_low_part (match_operand:HI 0 "general_operand" "=dm")) [(set (strict_low_part (match_operand:HI 0 "general_operand" "=dm"))
(match_operand:HI 1 "general_operand" "d"))] (match_operand:HI 1 "general_operand" "d"))]
"" ""
...@@ -986,15 +1132,20 @@ check_label_emit (); ...@@ -986,15 +1132,20 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STH %1,%0\"; return \"STH %1,%0\";
}") }"
[(set_attr "length" "8")]
)
; ;
; movdf instruction pattern(s). ; movdf instruction pattern(s).
; ;
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "r_or_s_operand" "=fm,fm,*dm") ;; [(set (match_operand:DF 0 "r_or_s_operand" "=fm,fm,*dm")
(match_operand:DF 1 "r_or_s_operand" "fmF,*dm,fmF"))] ;; (match_operand:DF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
[(set (match_operand:DF 0 "general_operand" "=f,m,fS,*dS,???d")
(match_operand:DF 1 "general_operand" "fmF,fF,*dS,fSF,???d"))]
"TARGET_CHAR_INSTRUCTIONS" "TARGET_CHAR_INSTRUCTIONS"
"* "*
{ {
...@@ -1027,6 +1178,11 @@ check_label_emit (); ...@@ -1027,6 +1178,11 @@ check_label_emit ();
mvs_check_page (0, 12, 0); mvs_check_page (0, 12, 0);
return \"STD %1,140(,13)\;LM %0,%N0,140(13)\"; return \"STD %1,140(,13)\;LM %0,%N0,140(13)\";
} }
if (REG_P (operands[1]))
{
mvs_check_page (0, 4, 0);
return \"LR %0,%1\;LR %N0,%N1\";
}
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LM %0,%N0,%1\"; return \"LM %0,%N0,%1\";
} }
...@@ -1041,12 +1197,17 @@ check_label_emit (); ...@@ -1041,12 +1197,17 @@ check_label_emit ();
return \"STM %1,%N1,%0\"; return \"STM %1,%N1,%0\";
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(8,%R0),%1\"; return \"MVC %O0(8,%R0),%W1\";
}") }"
[(set_attr "length" "12")]
)
(define_insn "movdf" (define_insn "movdf"
[(set (match_operand:DF 0 "general_operand" "=f,fm,m,*d") ;; [(set (match_operand:DF 0 "general_operand" "=f,fm,m,*d")
(match_operand:DF 1 "general_operand" "fmF,*d,f,fmF"))] ;; (match_operand:DF 1 "general_operand" "fmF,*d,f,fmF"))]
[(set (match_operand:DF 0 "general_operand" "=f,m,fS,*d,???d")
(match_operand:DF 1 "general_operand" "fmF,f,*d,SfF,???d"))]
"" ""
"* "*
{ {
...@@ -1079,6 +1240,11 @@ check_label_emit (); ...@@ -1079,6 +1240,11 @@ check_label_emit ();
mvs_check_page (0, 12, 0); mvs_check_page (0, 12, 0);
return \"STD %1,140(,13)\;LM %0,%N0,140(13)\"; return \"STD %1,140(,13)\;LM %0,%N0,140(13)\";
} }
if (REG_P (operands[1]))
{
mvs_check_page (0, 4, 0);
return \"LR %0,%1\;LR %N0,%N1\";
}
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LM %0,%N0,%1\"; return \"LM %0,%N0,%1\";
} }
...@@ -1089,15 +1255,22 @@ check_label_emit (); ...@@ -1089,15 +1255,22 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STM %1,%N1,%0\"; return \"STM %1,%N1,%0\";
}") }"
[(set_attr "length" "12")]
)
; ;
; movsf instruction pattern(s). ; movsf instruction pattern(s).
; ;
(define_insn "" (define_insn ""
[(set (match_operand:SF 0 "r_or_s_operand" "=fm,fm,*dm") ;; [(set (match_operand:SF 0 "r_or_s_operand" "=fm,fm,*dm")
(match_operand:SF 1 "r_or_s_operand" "fmF,*dm,fmF"))] ;; (match_operand:SF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
;; [(set (match_operand:SF 0 "general_operand" "=f,m,fm,*d,S")
;; (match_operand:SF 1 "general_operand" "fmF,fF,*d,fmF,S"))]
[(set (match_operand:SF 0 "general_operand" "=f*d,fm,S,???d")
(match_operand:SF 1 "general_operand" "fmF,fF*d,S,???d"))]
"TARGET_CHAR_INSTRUCTIONS" "TARGET_CHAR_INSTRUCTIONS"
"* "*
{ {
...@@ -1130,6 +1303,11 @@ check_label_emit (); ...@@ -1130,6 +1303,11 @@ check_label_emit ();
mvs_check_page (0, 8, 0); mvs_check_page (0, 8, 0);
return \"STE %1,140(,13)\;L %0,140(,13)\"; return \"STE %1,140(,13)\;L %0,140(,13)\";
} }
if (REG_P (operands[1]))
{
mvs_check_page (0, 2, 0);
return \"LR %0,%1\";
}
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"L %0,%1\"; return \"L %0,%1\";
} }
...@@ -1145,7 +1323,9 @@ check_label_emit (); ...@@ -1145,7 +1323,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(4,%R0),%1\"; return \"MVC %O0(4,%R0),%1\";
}") }"
[(set_attr "length" "8")]
)
(define_insn "movsf" (define_insn "movsf"
[(set (match_operand:SF 0 "general_operand" "=f,fm,m,*d") [(set (match_operand:SF 0 "general_operand" "=f,fm,m,*d")
...@@ -1192,11 +1372,67 @@ check_label_emit (); ...@@ -1192,11 +1372,67 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"ST %1,%0\"; return \"ST %1,%0\";
}"
[(set_attr "length" "8")]
)
;
; clrstrsi instruction pattern(s).
; memset a block of bytes to zero.
; block must be less than 16M (24 bits) in length
;
(define_expand "clrstrsi"
[(set (match_operand:BLK 0 "general_operand" "g")
(const_int 0))
(use (match_operand:SI 1 "general_operand" ""))
(match_operand 2 "" "")]
""
"
{
/*
XXX bogus, i think, unless change_address has a side effet we need
rtx op0;
op0 = XEXP (operands[0], 0);
if (GET_CODE (op0) == REG
|| (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == REG
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& (unsigned) INTVAL (XEXP (op0, 1)) < 4096))
op0 = operands[0];
else
op0 = change_address (operands[0], VOIDmode,
copy_to_mode_reg (SImode, op0));
*/
{
/* implementation suggested by Richard Henderson <rth@cygnus.com> */
rtx reg1 = gen_reg_rtx (DImode);
rtx reg2 = gen_reg_rtx (DImode);
rtx mem1 = operands[0];
rtx zippo = gen_rtx_CONST_INT (SImode, 0);
rtx len = operands[1];
if (!CONSTANT_P (len))
len = force_reg (SImode, len);
/* Load up the address+length pairs. */
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
force_operand (XEXP (mem1, 0), NULL_RTX));
emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), zippo);
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), zippo);
/* Copy! */
emit_insn (gen_movstrsi_1 (reg1, reg2));
}
DONE;
}") }")
; ;
; movstrsi instruction pattern(s). ; movstrsi instruction pattern(s).
; ; block must be less than 16M (24 bits) in length
(define_expand "movstrsi" (define_expand "movstrsi"
[(set (match_operand:BLK 0 "general_operand" "") [(set (match_operand:BLK 0 "general_operand" "")
...@@ -1229,27 +1465,35 @@ check_label_emit (); ...@@ -1229,27 +1465,35 @@ check_label_emit ();
copy_to_mode_reg (SImode, op1)); copy_to_mode_reg (SImode, op1));
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 256) if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 256)
emit_insn (gen_rtx (PARALLEL, VOIDmode, emit_insn (gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, gen_rtvec (2,
gen_rtx (SET, VOIDmode, op0, op1), gen_rtx_SET (VOIDmode, op0, op1),
gen_rtx (USE, VOIDmode, operands[2])))); gen_rtx_USE (VOIDmode, operands[2]))));
else else
{ {
/* implementation provided by Richard Henderson <rth@cygnus.com> */
rtx reg1 = gen_reg_rtx (DImode); rtx reg1 = gen_reg_rtx (DImode);
rtx reg2 = gen_reg_rtx (DImode); rtx reg2 = gen_reg_rtx (DImode);
rtx subreg = gen_rtx (SUBREG, SImode, reg1, 1); rtx mem1 = operands[0];
rtx mem2 = operands[1];
emit_insn (gen_rtx (SET, VOIDmode, subreg, operands[2])); rtx len = operands[2];
emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, reg2, 1), if (!CONSTANT_P (len))
subreg)); len = force_reg (SImode, len);
emit_insn (gen_rtx (PARALLEL, VOIDmode,
gen_rtvec (5, /* Load up the address+length pairs. */
gen_rtx (SET, VOIDmode, op0, op1), emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
gen_rtx (USE, VOIDmode, reg1), emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
gen_rtx (USE, VOIDmode, reg2), force_operand (XEXP (mem1, 0), NULL_RTX));
gen_rtx (CLOBBER, VOIDmode, reg1), emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);
gen_rtx (CLOBBER, VOIDmode, reg2))));
emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0),
force_operand (XEXP (mem2, 0), NULL_RTX));
emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len);
/* Copy! */
emit_insn (gen_movstrsi_1 (reg1, reg2));
} }
DONE; DONE;
}") }")
...@@ -1266,24 +1510,28 @@ check_label_emit (); ...@@ -1266,24 +1510,28 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"MVC %O0(%c2,%R0),%1\"; return \"MVC %O0(%c2,%R0),%1\";
}") }"
[(set_attr "length" "6")]
)
; Move a block that is larger than 255 bytes in length. ; Move a block that is larger than 255 bytes in length.
(define_insn "" (define_insn "movstrsi_1"
[(set (match_operand:BLK 0 "general_operand" "=m") [(set (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "+d") 0))
(match_operand:BLK 1 "general_operand" "m")) (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0)))
(use (match_operand:DI 2 "register_operand" "d")) (use (match_dup 0))
(use (match_operand:DI 3 "register_operand" "d")) (use (match_dup 1))
(clobber (match_dup 2)) (clobber (match_dup 0))
(clobber (match_dup 3))] (clobber (match_dup 1))]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
mvs_check_page (0, 10, 0); mvs_check_page (0, 2, 0);
return \"LA %2,%0\;LA %3,%1\;MVCL %2,%3\"; return \"MVCL %0,%1\";
}") }"
[(set_attr "length" "2")]
)
;; ;;
;;- Conversion instructions. ;;- Conversion instructions.
...@@ -1294,34 +1542,34 @@ check_label_emit (); ...@@ -1294,34 +1542,34 @@ check_label_emit ();
; ;
(define_expand "extendsidi2" (define_expand "extendsidi2"
[(set (match_operand:DI 0 "general_operand" "") [(set (match_operand:DI 0 "register_operand" "=d")
(sign_extend:DI (match_operand:SI 1 "general_operand" "")))] (sign_extend:DI (match_operand:SI 1 "general_operand" "")))]
"" ""
" "
{ {
if (GET_CODE (operands[1]) != CONST_INT) if (GET_CODE (operands[1]) != CONST_INT)
{ {
emit_insn (gen_rtx (SET, VOIDmode, emit_insn (gen_rtx_SET (VOIDmode,
operand_subword (operands[0], 0, 1, DImode), operands[1])); operand_subword (operands[0], 0, 1, DImode), operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (ASHIFTRT, DImode, operands[0], gen_rtx_ASHIFTRT (DImode, operands[0],
GEN_INT (32)))); gen_rtx_CONST_INT (SImode, 32))));
} }
else else
{ {
if (INTVAL (operands[1]) < 0) if (INTVAL (operands[1]) < 0)
{ {
emit_insn (gen_rtx (SET, VOIDmode, emit_insn (gen_rtx_SET (VOIDmode,
operand_subword (operands[0], 0, 1, DImode), operand_subword (operands[0], 0, 1, DImode),
GEN_INT (-1))); gen_rtx_CONST_INT (SImode, -1)));
} }
else else
{ {
emit_insn (gen_rtx (SET, VOIDmode, emit_insn (gen_rtx_SET (VOIDmode,
operand_subword (operands[0], 0, 1, DImode), operand_subword (operands[0], 0, 1, DImode),
GEN_INT (0))); gen_rtx_CONST_INT (SImode, 0)));
} }
emit_insn (gen_rtx (SET, VOIDmode, gen_lowpart (SImode, operands[0]), emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (SImode, operands[0]),
operands[1])); operands[1]));
} }
DONE; DONE;
...@@ -1343,7 +1591,7 @@ check_label_emit (); ...@@ -1343,7 +1591,7 @@ check_label_emit ();
if (REG_P (operands[1])) if (REG_P (operands[1]))
if (REGNO (operands[0]) != REGNO (operands[1])) if (REGNO (operands[0]) != REGNO (operands[1]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 10, 0);
return \"LR %0,%1\;SLL %0,16\;SRA %0,16\"; return \"LR %0,%1\;SLL %0,16\;SRA %0,16\";
} }
else else
...@@ -1358,7 +1606,7 @@ check_label_emit (); ...@@ -1358,7 +1606,7 @@ check_label_emit ();
&& (unsigned) INTVAL (operands[1]) < 4096) && (unsigned) INTVAL (operands[1]) < 4096)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
...@@ -1368,9 +1616,11 @@ check_label_emit (); ...@@ -1368,9 +1616,11 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LH %0,%1\"; return \"LH %0,%1\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 12, 0);
return \"SLL %1,16\;SRA %1,16\;ST %1,%0\"; return \"SLL %1,16\;SRA %1,16\;ST %1,%0\";
}") }"
[(set_attr "length" "12")]
)
; ;
; extendqisi2 instruction pattern(s). ; extendqisi2 instruction pattern(s).
...@@ -1396,7 +1646,9 @@ check_label_emit (); ...@@ -1396,7 +1646,9 @@ check_label_emit ();
} }
mvs_check_page (0, 12, 0); mvs_check_page (0, 12, 0);
return \"IC %0,%1\;SLL %0,24\;SRA %0,24\"; return \"IC %0,%1\;SLL %0,24\;SRA %0,24\";
}") }"
[(set_attr "length" "12")]
)
; ;
; extendqihi2 instruction pattern(s). ; extendqihi2 instruction pattern(s).
...@@ -1422,23 +1674,25 @@ check_label_emit (); ...@@ -1422,23 +1674,25 @@ check_label_emit ();
} }
mvs_check_page (0, 12, 0); mvs_check_page (0, 12, 0);
return \"IC %0,%1\;SLL %0,24\;SRA %0,24\"; return \"IC %0,%1\;SLL %0,24\;SRA %0,24\";
}") }"
[(set_attr "length" "12")]
)
; ;
; zero_extendsidi2 instruction pattern(s). ; zero_extendsidi2 instruction pattern(s).
; ;
(define_expand "zero_extendsidi2" (define_expand "zero_extendsidi2"
[(set (match_operand:DI 0 "general_operand" "") [(set (match_operand:DI 0 "register_operand" "=d")
(zero_extend:DI (match_operand:SI 1 "general_operand" "")))] (zero_extend:DI (match_operand:SI 1 "general_operand" "")))]
"" ""
" "
{ {
emit_insn (gen_rtx (SET, VOIDmode, emit_insn (gen_rtx_SET (VOIDmode,
operand_subword (operands[0], 0, 1, DImode), operands[1])); operand_subword (operands[0], 0, 1, DImode), operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (LSHIFTRT, DImode, operands[0], gen_rtx_LSHIFTRT (DImode, operands[0],
GEN_INT (32)))); gen_rtx_CONST_INT (SImode, 32))));
DONE; DONE;
}") }")
...@@ -1453,10 +1707,13 @@ check_label_emit (); ...@@ -1453,10 +1707,13 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_SET (operands[0], operands[1]); /* AND only sets zero/not-zero bits not the arithmetic bits ... */
CC_STATUS_INIT;
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"N %1,=X'0000FFFF'\"; return \"N %1,=X'0000FFFF'\";
}") }"
[(set_attr "length" "4")]
)
; ;
; zero_extendqisi2 instruction pattern(s). ; zero_extendqisi2 instruction pattern(s).
...@@ -1471,19 +1728,22 @@ check_label_emit (); ...@@ -1471,19 +1728,22 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
if (REG_P (operands[1])) if (REG_P (operands[1]))
{ {
CC_STATUS_SET (operands[0], operands[1]); /* AND only sets zero/not-zero bits not the arithmetic bits ... */
CC_STATUS_INIT;
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"N %0,=X'000000FF'\"; return \"N %0,=X'000000FF'\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 8, 0); mvs_check_page (0, 8, 0);
return \"SLR %0,%0\;IC %0,%1\"; return \"SLR %0,%0\;IC %0,%1\";
}") }"
[(set_attr "length" "8")]
)
; ;
; zero_extendqihi2 instruction pattern(s). ; zero_extendqihi2 instruction pattern(s).
...@@ -1498,19 +1758,22 @@ check_label_emit (); ...@@ -1498,19 +1758,22 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
if (REG_P (operands[1])) if (REG_P (operands[1]))
{ {
CC_STATUS_SET (operands[0], operands[1]); /* AND only sets zero/not-zero bits not the arithmetic bits ... */
CC_STATUS_INIT;
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"N %0,=X'000000FF'\"; return \"N %0,=X'000000FF'\";
} }
if (GET_CODE (operands[1]) == CONST_INT) if (GET_CODE (operands[1]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c1\"; return \"LA %0,%c1(0,0)\";
} }
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 8, 0); mvs_check_page (0, 8, 0);
return \"SLR %0,%0\;IC %0,%1\"; return \"SLR %0,%0\;IC %0,%1\";
}") }"
[(set_attr "length" "8")]
)
; ;
; truncsihi2 instruction pattern(s). ; truncsihi2 instruction pattern(s).
...@@ -1531,7 +1794,9 @@ check_label_emit (); ...@@ -1531,7 +1794,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"STH %1,%0\"; return \"STH %1,%0\";
}") }"
[(set_attr "length" "8")]
)
; ;
; fix_truncdfsi2 instruction pattern(s). ; fix_truncdfsi2 instruction pattern(s).
...@@ -1539,7 +1804,7 @@ check_label_emit (); ...@@ -1539,7 +1804,7 @@ check_label_emit ();
(define_insn "fix_truncdfsi2" (define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
(fix:SI (truncate:DF (match_operand:DF 1 "general_operand" "f")))) (fix:SI (truncate:DF (match_operand:DF 1 "general_operand" "+f"))))
(clobber (reg:DF 16))] (clobber (reg:DF 16))]
"" ""
"* "*
...@@ -1553,7 +1818,9 @@ check_label_emit (); ...@@ -1553,7 +1818,9 @@ check_label_emit ();
} }
mvs_check_page (0, 14, 8); mvs_check_page (0, 14, 8);
return \"LDR 0,%1\;AD 0,=XL8'4F08000000000000'\;STD 0,140(,13)\;L %0,144(,13)\"; return \"LDR 0,%1\;AD 0,=XL8'4F08000000000000'\;STD 0,140(,13)\;L %0,144(,13)\";
}") }"
[(set_attr "length" "14")]
)
; ;
; floatsidf2 instruction pattern(s). ; floatsidf2 instruction pattern(s).
...@@ -1571,7 +1838,9 @@ check_label_emit (); ...@@ -1571,7 +1838,9 @@ check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 16, 8); mvs_check_page (0, 16, 8);
return \"ST %1,508(,12)\;XI 508(12),128\;LD %0,504(,12)\;SD %0,=XL8'4E00000080000000'\"; return \"ST %1,508(,12)\;XI 508(12),128\;LD %0,504(,12)\;SD %0,=XL8'4E00000080000000'\";
}") }"
[(set_attr "length" "16")]
)
; ;
; truncdfsf2 instruction pattern(s). ; truncdfsf2 instruction pattern(s).
...@@ -1586,7 +1855,9 @@ check_label_emit (); ...@@ -1586,7 +1855,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LRER %0,%1\"; return \"LRER %0,%1\";
}") }"
[(set_attr "length" "2")]
)
; ;
; extendsfdf2 instruction pattern(s). ; extendsfdf2 instruction pattern(s).
...@@ -1612,7 +1883,9 @@ check_label_emit (); ...@@ -1612,7 +1883,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"SDR %0,%0\;LE %0,%1\"; return \"SDR %0,%0\;LE %0,%1\";
}") }"
[(set_attr "length" "10")]
)
;; ;;
;;- Add instructions. ;;- Add instructions.
...@@ -1621,39 +1894,41 @@ check_label_emit (); ...@@ -1621,39 +1894,41 @@ check_label_emit ();
; ;
; adddi3 instruction pattern(s). ; adddi3 instruction pattern(s).
; ;
;
(define_expand "adddi3" ;(define_expand "adddi3"
[(set (match_operand:DI 0 "general_operand" "") ; [(set (match_operand:DI 0 "general_operand" "")
(plus:DI (match_operand:DI 1 "general_operand" "") ; (plus:DI (match_operand:DI 1 "general_operand" "")
(match_operand:DI 2 "general_operand" "")))] ; (match_operand:DI 2 "general_operand" "")))]
"" ; ""
" ; "
{ ;{
rtx label = gen_label_rtx (); ; rtx label = gen_label_rtx ();
rtx op0_high = operand_subword (operands[0], 0, 1, DImode); ; rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
rtx op0_low = gen_lowpart (SImode, operands[0]); ; rtx op0_low = gen_lowpart (SImode, operands[0]);
;
emit_insn (gen_rtx (SET, VOIDmode, op0_high, ; emit_insn (gen_rtx_SET (VOIDmode, op0_high,
gen_rtx (PLUS, SImode, ; gen_rtx_PLUS (SImode,
operand_subword (operands[1], 0, 1, DImode), ; operand_subword (operands[1], 0, 1, DImode),
operand_subword (operands[2], 0, 1, DImode)))); ; operand_subword (operands[2], 0, 1, DImode))));
emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, ; emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
gen_rtx (SET, VOIDmode, op0_low, ; gen_rtx_SET (VOIDmode, op0_low,
gen_rtx (PLUS, SImode, gen_lowpart (SImode, operands[1]), ; gen_rtx_PLUS (SImode, gen_lowpart (SImode, operands[1]),
gen_lowpart (SImode, operands[2]))), ; gen_lowpart (SImode, operands[2]))),
gen_rtx (USE, VOIDmode, gen_rtx (LABEL_REF, VOIDmode, label))))); ; gen_rtx_USE (VOIDmode, gen_rtx_LABEL_REF (VOIDmode, label)))));
emit_insn (gen_rtx (SET, VOIDmode, op0_high, ; emit_insn (gen_rtx_SET (VOIDmode, op0_high,
gen_rtx (PLUS, SImode, op0_high, ; gen_rtx_PLUS (SImode, op0_high,
GEN_INT (1)))); ; gen_rtx_CONST_INT (SImode, 1))));
emit_label (label); ; emit_label (label);
DONE; ; DONE;
}") ;}")
(define_insn "" (define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
(plus:SI (match_operand:SI 1 "general_operand" "%0") (plus:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g"))) (match_operand:SI 2 "general_operand" "g")))
(use (label_ref (match_operand 3 "" "")))] (use (label_ref (match_operand 3 "" "")))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
...@@ -1686,7 +1961,9 @@ check_label_emit (); ...@@ -1686,7 +1961,9 @@ check_label_emit ();
return \"AL %0,%2\;L 14,=A(%l3)\;BCR 12,14\"; return \"AL %0,%2\;L 14,=A(%l3)\;BCR 12,14\";
} }
return \"AL %0,%2\;BC 12,%l3\"; return \"AL %0,%2\;BC 12,%l3\";
}") }"
[(set_attr "length" "10")]
)
; ;
; addsi3 instruction pattern(s). ; addsi3 instruction pattern(s).
...@@ -1706,10 +1983,12 @@ check_label_emit (); ...@@ -1706,10 +1983,12 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* add assumes CC but LA doesnt set CC */
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c2(,%1)\"; return \"LA %0,%c2(,%1)\";
}") }"
[(set_attr "length" "4")]
)
; This insn handles additions that are relative to the frame pointer. ; This insn handles additions that are relative to the frame pointer.
...@@ -1723,17 +2002,28 @@ check_label_emit (); ...@@ -1723,17 +2002,28 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
if ((unsigned) INTVAL (operands[2]) < 4096) if ((unsigned) INTVAL (operands[2]) < 4096)
{ {
CC_STATUS_INIT; /* add assumes CC but LA doesnt set CC */
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"LA %0,%c2(,%1)\"; return \"LA %0,%c2(,%1)\";
} }
if (REGNO (operands[1]) == REGNO (operands[0])) if (REGNO (operands[1]) == REGNO (operands[0]))
{ {
CC_STATUS_INIT;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"A %0,%2\"; return \"A %0,%2\";
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"L %0,%2\;AR %0,%1\"; return \"L %0,%2\;AR %0,%1\";
}") }"
[(set_attr "length" "6")]
)
;;
;; The CC status bits for the arithmetic instructions are handled
;; in the NOTICE_UPDATE_CC macro (yeah???) and so they do not need
;; to be set below. They only need to be invalidated if *not* set
;; (e.g. by BCTR) ... yeah I think that's right ...
;;
(define_insn "addsi3" (define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
...@@ -1752,14 +2042,16 @@ check_label_emit (); ...@@ -1752,14 +2042,16 @@ check_label_emit ();
{ {
if (INTVAL (operands[2]) == -1) if (INTVAL (operands[2]) == -1)
{ {
CC_STATUS_INIT; CC_STATUS_INIT; /* add assumes CC but BCTR doesnt set CC */
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"BCTR %0,0\"; return \"BCTR %0,0\";
} }
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"A %0,%2\"; return \"A %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; addhi3 instruction pattern(s). ; addhi3 instruction pattern(s).
...@@ -1782,7 +2074,7 @@ check_label_emit (); ...@@ -1782,7 +2074,7 @@ check_label_emit ();
{ {
if (INTVAL (operands[2]) == -1) if (INTVAL (operands[2]) == -1)
{ {
CC_STATUS_INIT; CC_STATUS_INIT; /* add assumes CC but BCTR doesnt set CC */
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"BCTR %0,0\"; return \"BCTR %0,0\";
} }
...@@ -1791,7 +2083,9 @@ check_label_emit (); ...@@ -1791,7 +2083,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"AH %0,%2\"; return \"AH %0,%2\";
}") }"
[(set_attr "length" "8")]
)
; ;
; addqi3 instruction pattern(s). ; addqi3 instruction pattern(s).
...@@ -1805,12 +2099,14 @@ check_label_emit (); ...@@ -1805,12 +2099,14 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* add assumes CC but LA doesnt set CC */
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"LA %0,0(%1,%2)\"; return \"LA %0,0(%1,%2)\";
return \"LA %0,%B2(,%1)\"; return \"LA %0,%B2(,%1)\";
}") }"
[(set_attr "length" "4")]
)
; ;
; adddf3 instruction pattern(s). ; adddf3 instruction pattern(s).
...@@ -1831,7 +2127,9 @@ check_label_emit (); ...@@ -1831,7 +2127,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"AD %0,%2\"; return \"AD %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; addsf3 instruction pattern(s). ; addsf3 instruction pattern(s).
...@@ -1852,7 +2150,9 @@ check_label_emit (); ...@@ -1852,7 +2150,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"AE %0,%2\"; return \"AE %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Subtract instructions. ;;- Subtract instructions.
...@@ -1861,41 +2161,43 @@ check_label_emit (); ...@@ -1861,41 +2161,43 @@ check_label_emit ();
; ;
; subdi3 instruction pattern(s). ; subdi3 instruction pattern(s).
; ;
;
(define_expand "subdi3" ;(define_expand "subdi3"
[(set (match_operand:DI 0 "general_operand" "") ; [(set (match_operand:DI 0 "general_operand" "")
(minus:DI (match_operand:DI 1 "general_operand" "") ; (minus:DI (match_operand:DI 1 "general_operand" "")
(match_operand:DI 2 "general_operand" "")))] ; (match_operand:DI 2 "general_operand" "")))]
"" ; ""
" ; "
{ ;{
rtx label = gen_label_rtx (); ; rtx label = gen_label_rtx ();
rtx op0_high = operand_subword (operands[0], 0, 1, DImode); ; rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
rtx op0_low = gen_lowpart (SImode, operands[0]); ; rtx op0_low = gen_lowpart (SImode, operands[0]);
;
emit_insn (gen_rtx (SET, VOIDmode, op0_high, ; emit_insn (gen_rtx_SET (VOIDmode, op0_high,
gen_rtx (MINUS, SImode, ; gen_rtx_MINUS (SImode,
operand_subword (operands[1], 0, 1, DImode), ; operand_subword (operands[1], 0, 1, DImode),
operand_subword (operands[2], 0, 1, DImode)))); ; operand_subword (operands[2], 0, 1, DImode))));
emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, ; emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
gen_rtx (SET, VOIDmode, op0_low, ; gen_rtx_SET (VOIDmode, op0_low,
gen_rtx (MINUS, SImode, ; gen_rtx_MINUS (SImode,
gen_lowpart (SImode, operands[1]), ; gen_lowpart (SImode, operands[1]),
gen_lowpart (SImode, operands[2]))), ; gen_lowpart (SImode, operands[2]))),
gen_rtx (USE, VOIDmode, ; gen_rtx_USE (VOIDmode,
gen_rtx (LABEL_REF, VOIDmode, label))))); ; gen_rtx_LABEL_REF (VOIDmode, label)))));
emit_insn (gen_rtx (SET, VOIDmode, op0_high, ; emit_insn (gen_rtx_SET (VOIDmode, op0_high,
gen_rtx (MINUS, SImode, op0_high, ; gen_rtx_MINUS (SImode, op0_high,
GEN_INT (1)))); ; gen_rtx_CONST_INT (SImode, 1))));
emit_label (label); ; emit_label (label);
DONE; ; DONE;
}") ;}")
(define_insn "" (define_insn ""
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
(minus:SI (match_operand:SI 1 "general_operand" "0") (minus:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "g"))) (match_operand:SI 2 "general_operand" "g")))
(use (label_ref (match_operand 3 "" "")))] (use (label_ref (match_operand 3 "" "")))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
...@@ -1929,7 +2231,9 @@ check_label_emit (); ...@@ -1929,7 +2231,9 @@ check_label_emit ();
return \"SL %0,%2\;L 14,=A(%l3)\;BCR 12,14\"; return \"SL %0,%2\;L 14,=A(%l3)\;BCR 12,14\";
} }
return \"SL %0,%2\;BC 12,%l3\"; return \"SL %0,%2\;BC 12,%l3\";
}") }"
[(set_attr "length" "10")]
)
; ;
; subsi3 instruction pattern(s). ; subsi3 instruction pattern(s).
...@@ -1950,13 +2254,15 @@ check_label_emit (); ...@@ -1950,13 +2254,15 @@ check_label_emit ();
} }
if (operands[2] == const1_rtx) if (operands[2] == const1_rtx)
{ {
CC_STATUS_INIT; CC_STATUS_INIT; /* subtract assumes CC but BCTR doesnt set CC */
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"BCTR %0,0\"; return \"BCTR %0,0\";
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"S %0,%2\"; return \"S %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; subhi3 instruction pattern(s). ; subhi3 instruction pattern(s).
...@@ -1977,7 +2283,7 @@ check_label_emit (); ...@@ -1977,7 +2283,7 @@ check_label_emit ();
} }
if (operands[2] == const1_rtx) if (operands[2] == const1_rtx)
{ {
CC_STATUS_INIT; CC_STATUS_INIT; /* subtract assumes CC but BCTR doesnt set CC */
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"BCTR %0,0\"; return \"BCTR %0,0\";
} }
...@@ -1988,7 +2294,9 @@ check_label_emit (); ...@@ -1988,7 +2294,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"SH %0,%2\"; return \"SH %0,%2\";
}") }"
[(set_attr "length" "8")]
)
; ;
; subqi3 instruction pattern(s). ; subqi3 instruction pattern(s).
...@@ -2003,13 +2311,13 @@ check_label_emit (); ...@@ -2003,13 +2311,13 @@ check_label_emit ();
{ {
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (MINUS, QImode, operands[1], operands[2]))); gen_rtx_MINUS (QImode, operands[1], operands[2])));
} }
else else
{ {
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (PLUS, QImode, operands[1], gen_rtx_PLUS (QImode, operands[1],
negate_rtx (QImode, operands[2])))); negate_rtx (QImode, operands[2]))));
} }
DONE; DONE;
...@@ -2023,10 +2331,11 @@ check_label_emit (); ...@@ -2023,10 +2331,11 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT;
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"SR %0,%2\"; return \"SR %0,%2\";
}") }"
[(set_attr "length" "2")]
)
; ;
; subdf3 instruction pattern(s). ; subdf3 instruction pattern(s).
...@@ -2047,7 +2356,9 @@ check_label_emit (); ...@@ -2047,7 +2356,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"SD %0,%2\"; return \"SD %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; subsf3 instruction pattern(s). ; subsf3 instruction pattern(s).
...@@ -2068,7 +2379,9 @@ check_label_emit (); ...@@ -2068,7 +2379,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"SE %0,%2\"; return \"SE %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Multiply instructions. ;;- Multiply instructions.
...@@ -2088,31 +2401,43 @@ check_label_emit (); ...@@ -2088,31 +2401,43 @@ check_label_emit ();
if (GET_CODE (operands[1]) == CONST_INT if (GET_CODE (operands[1]) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K')) && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
{ {
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (MULT, SImode, operands[2], operands[1]))); gen_rtx_MULT (SImode, operands[2], operands[1])));
} }
else if (GET_CODE (operands[2]) == CONST_INT else if (GET_CODE (operands[2]) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')) && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))
{ {
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (MULT, SImode, operands[1], operands[2]))); gen_rtx_MULT (SImode, operands[1], operands[2])));
} }
else else
{ {
rtx r = gen_reg_rtx (DImode); rtx r = gen_reg_rtx (DImode);
emit_insn (gen_rtx (SET, VOIDmode, /* XXX trouble. Below we generate some rtx's that model what
gen_rtx (SUBREG, SImode, r, 1), operands[1])); * is really supposed to happen with multiply on the 370/390
emit_insn (gen_rtx (SET, VOIDmode, r, * hardware, and that is all well & god. However, during optimization
gen_rtx (MULT, SImode, r, operands[2]))); * it can happen that the two operands are exchanged (after all,
emit_insn (gen_rtx (SET, VOIDmode, operands[0], * multiplication is commutitive), in which case the doubleword
gen_rtx (SUBREG, SImode, r, 1))); * ends up in memory and everything is hosed. The gen_reg_rtx
* should have kept it in a reg ... We hack around this
* below, in the M/MR isntruction pattern, and constrain it to
* \"di\" instead of \"g\". But this still ends up with lots & lots of
* movement between registers & memory and is an awful waste.
* Dunno how to untwist it elegantly; but it seems to work for now.
*/
emit_insn (gen_rtx_SET (VOIDmode,
gen_rtx_SUBREG (SImode, r, 1), operands[1]));
emit_insn (gen_rtx_SET (VOIDmode, r,
gen_rtx_MULT (SImode, r, operands[2])));
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_SUBREG (SImode, r, 1)));
} }
DONE; DONE;
}") }")
(define_insn "" (define_insn ""
[(set (match_operand:SI 0 "register_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
(mult:SI (match_operand:SI 1 "general_operand" "%0") (mult:SI (match_operand:SI 1 "general_operand" "%0")
(match_operand:SI 2 "immediate_operand" "K")))] (match_operand:SI 2 "immediate_operand" "K")))]
"" ""
...@@ -2121,12 +2446,16 @@ check_label_emit (); ...@@ -2121,12 +2446,16 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"MH %0,%H2\"; return \"MH %0,%H2\";
}") }"
[(set_attr "length" "4")]
)
;; XXX see comments in mulsi above.
(define_insn "" (define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d") [(set (match_operand:DI 0 "register_operand" "=d")
(mult:DI (match_operand:DI 1 "general_operand" "%0") (mult:SI (match_operand:DI 1 "general_operand" "%0")
(match_operand:SI 2 "general_operand" "g")))] ;; XXX see above (match_operand:SI 2 "general_operand" "g")))]
(match_operand:SI 2 "general_operand" "di")))]
"" ""
"* "*
{ {
...@@ -2138,7 +2467,9 @@ check_label_emit (); ...@@ -2138,7 +2467,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"M %0,%2\"; return \"M %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; muldf3 instruction pattern(s). ; muldf3 instruction pattern(s).
...@@ -2159,7 +2490,9 @@ check_label_emit (); ...@@ -2159,7 +2490,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"MD %0,%2\"; return \"MD %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; mulsf3 instruction pattern(s). ; mulsf3 instruction pattern(s).
...@@ -2180,7 +2513,9 @@ check_label_emit (); ...@@ -2180,7 +2513,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"ME %0,%2\"; return \"ME %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Divide instructions. ;;- Divide instructions.
...@@ -2200,10 +2535,10 @@ check_label_emit (); ...@@ -2200,10 +2535,10 @@ check_label_emit ();
rtx r = gen_reg_rtx (DImode); rtx r = gen_reg_rtx (DImode);
emit_insn (gen_extendsidi2 (r, operands[1])); emit_insn (gen_extendsidi2 (r, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, r, emit_insn (gen_rtx_SET (VOIDmode, r,
gen_rtx (DIV, SImode, r, operands[2]))); gen_rtx_DIV (SImode, r, operands[2])));
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (SUBREG, SImode, r, 1))); gen_rtx_SUBREG (SImode, r, 1)));
DONE; DONE;
}") }")
...@@ -2220,8 +2555,8 @@ check_label_emit (); ...@@ -2220,8 +2555,8 @@ check_label_emit ();
" "
{ {
rtx dr = gen_reg_rtx (DImode); rtx dr = gen_reg_rtx (DImode);
rtx dr_0 = gen_rtx (SUBREG, SImode, dr, 0); rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
rtx dr_1 = gen_rtx (SUBREG, SImode, dr, 1); rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1);
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
...@@ -2229,18 +2564,18 @@ check_label_emit (); ...@@ -2229,18 +2564,18 @@ check_label_emit ();
if (INTVAL (operands[2]) > 0) if (INTVAL (operands[2]) > 0)
{ {
emit_insn (gen_zero_extendsidi2 (dr, operands[1])); emit_insn (gen_zero_extendsidi2 (dr, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (DIV, SImode, dr, operands[2]))); gen_rtx_DIV (SImode, dr, operands[2])));
} }
else else
{ {
rtx label1 = gen_label_rtx (); rtx label1 = gen_label_rtx ();
emit_insn (gen_rtx (SET, VOIDmode, dr_0, operands[1])); emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, dr_1, const0_rtx)); emit_insn (gen_rtx_SET (VOIDmode, dr_1, const0_rtx));
emit_insn (gen_cmpsi (dr_0, operands[2])); emit_insn (gen_cmpsi (dr_0, operands[2]));
emit_jump_insn (gen_bltu (label1)); emit_jump_insn (gen_bltu (label1));
emit_insn (gen_rtx (SET, VOIDmode, dr_1, const1_rtx)); emit_insn (gen_rtx_SET (VOIDmode, dr_1, const1_rtx));
emit_label (label1); emit_label (label1);
} }
} }
...@@ -2251,28 +2586,29 @@ check_label_emit (); ...@@ -2251,28 +2586,29 @@ check_label_emit ();
rtx label3 = gen_label_rtx (); rtx label3 = gen_label_rtx ();
rtx sr = gen_reg_rtx (SImode); rtx sr = gen_reg_rtx (SImode);
emit_insn (gen_rtx (SET, VOIDmode, dr_0, operands[1])); emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, sr, operands[2])); emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
emit_insn (gen_rtx (SET, VOIDmode, dr_1, const0_rtx)); emit_insn (gen_rtx_SET (VOIDmode, dr_1, const0_rtx));
emit_insn (gen_cmpsi (sr, dr_0)); emit_insn (gen_cmpsi (sr, dr_0));
emit_jump_insn (gen_bgtu (label3)); emit_jump_insn (gen_bgtu (label3));
emit_insn (gen_cmpsi (sr, const1_rtx)); emit_insn (gen_cmpsi (sr, const1_rtx));
emit_jump_insn (gen_blt (label2)); emit_jump_insn (gen_blt (label2));
emit_insn (gen_cmpsi (sr, const1_rtx));
emit_jump_insn (gen_beq (label1)); emit_jump_insn (gen_beq (label1));
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (LSHIFTRT, DImode, dr, gen_rtx_LSHIFTRT (DImode, dr,
GEN_INT (32)))); gen_rtx_CONST_INT (SImode, 32))));
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (DIV, SImode, dr, sr))); gen_rtx_DIV (SImode, dr, sr)));
emit_jump_insn (gen_jump (label3)); emit_jump_insn (gen_jump (label3));
emit_label (label1); emit_label (label1);
emit_insn (gen_rtx (SET, VOIDmode, dr_1, dr_0)); emit_insn (gen_rtx_SET (VOIDmode, dr_1, dr_0));
emit_jump_insn (gen_jump (label3)); emit_jump_insn (gen_jump (label3));
emit_label (label2); emit_label (label2);
emit_insn (gen_rtx (SET, VOIDmode, dr_1, const1_rtx)); emit_insn (gen_rtx_SET (VOIDmode, dr_1, const1_rtx));
emit_label (label3); emit_label (label3);
} }
emit_insn (gen_rtx (SET, VOIDmode, operands[0], dr_1)); emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_1));
DONE; DONE;
}") }")
...@@ -2281,8 +2617,8 @@ check_label_emit (); ...@@ -2281,8 +2617,8 @@ check_label_emit ();
(define_insn "" (define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d") [(set (match_operand:DI 0 "register_operand" "=d")
(div:DI (match_operand:DI 1 "register_operand" "0") (div:SI (match_operand:DI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "")))] (match_operand:SI 2 "general_operand" "dm")))]
"" ""
"* "*
{ {
...@@ -2294,7 +2630,9 @@ check_label_emit (); ...@@ -2294,7 +2630,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"D %0,%2\"; return \"D %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; divdf3 instruction pattern(s). ; divdf3 instruction pattern(s).
...@@ -2315,7 +2653,9 @@ check_label_emit (); ...@@ -2315,7 +2653,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"DD %0,%2\"; return \"DD %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; divsf3 instruction pattern(s). ; divsf3 instruction pattern(s).
...@@ -2336,7 +2676,9 @@ check_label_emit (); ...@@ -2336,7 +2676,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"DE %0,%2\"; return \"DE %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Modulo instructions. ;;- Modulo instructions.
...@@ -2356,10 +2698,10 @@ check_label_emit (); ...@@ -2356,10 +2698,10 @@ check_label_emit ();
rtx r = gen_reg_rtx (DImode); rtx r = gen_reg_rtx (DImode);
emit_insn (gen_extendsidi2 (r, operands[1])); emit_insn (gen_extendsidi2 (r, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, r, emit_insn (gen_rtx_SET (VOIDmode, r,
gen_rtx (MOD, SImode, r, operands[2]))); gen_rtx_MOD (SImode, r, operands[2])));
emit_insn (gen_rtx (SET, VOIDmode, operands[0], emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (SUBREG, SImode, r, 0))); gen_rtx_SUBREG (SImode, r, 0)));
DONE; DONE;
}") }")
...@@ -2375,32 +2717,32 @@ check_label_emit (); ...@@ -2375,32 +2717,32 @@ check_label_emit ();
" "
{ {
rtx dr = gen_reg_rtx (DImode); rtx dr = gen_reg_rtx (DImode);
rtx dr_0 = gen_rtx (SUBREG, SImode, dr, 0); rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
rtx dr_1 = gen_rtx (SUBREG, SImode, dr, 1); rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1);
emit_insn (gen_rtx (SET, VOIDmode, dr_0, operands[1])); emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
if (INTVAL (operands[2]) > 0) if (INTVAL (operands[2]) > 0)
{ {
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (LSHIFTRT, DImode, dr, gen_rtx_LSHIFTRT (DImode, dr,
GEN_INT (32)))); gen_rtx_CONST_INT (SImode, 32))));
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (MOD, SImode, dr, operands[2]))); gen_rtx_MOD (SImode, dr, operands[2])));
} }
else else
{ {
rtx label1 = gen_label_rtx (); rtx label1 = gen_label_rtx ();
rtx sr = gen_reg_rtx (SImode); rtx sr = gen_reg_rtx (SImode);
emit_insn (gen_rtx (SET, VOIDmode, sr, operands[2])); emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
emit_insn (gen_cmpsi (dr_0, sr)); emit_insn (gen_cmpsi (dr_0, sr));
emit_jump_insn (gen_bltu (label1)); emit_jump_insn (gen_bltu (label1));
emit_insn (gen_rtx (SET, VOIDmode, sr, gen_rtx (ABS, SImode, sr))); emit_insn (gen_rtx_SET (VOIDmode, sr, gen_rtx_ABS (SImode, sr)));
emit_insn (gen_rtx (SET, VOIDmode, dr_0, emit_insn (gen_rtx_SET (VOIDmode, dr_0,
gen_rtx (PLUS, SImode, dr_0, sr))); gen_rtx_PLUS (SImode, dr_0, sr)));
emit_label (label1); emit_label (label1);
} }
} }
...@@ -2411,28 +2753,29 @@ check_label_emit (); ...@@ -2411,28 +2753,29 @@ check_label_emit ();
rtx label3 = gen_label_rtx (); rtx label3 = gen_label_rtx ();
rtx sr = gen_reg_rtx (SImode); rtx sr = gen_reg_rtx (SImode);
emit_insn (gen_rtx (SET, VOIDmode, dr_0, operands[1])); emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
emit_insn (gen_rtx (SET, VOIDmode, sr, operands[2])); emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
emit_insn (gen_cmpsi (sr, dr_0)); emit_insn (gen_cmpsi (sr, dr_0));
emit_jump_insn (gen_bgtu (label3)); emit_jump_insn (gen_bgtu (label3));
emit_insn (gen_cmpsi (sr, const1_rtx)); emit_insn (gen_cmpsi (sr, const1_rtx));
emit_jump_insn (gen_blt (label2)); emit_jump_insn (gen_blt (label2));
emit_insn (gen_cmpsi (sr, const1_rtx));
emit_jump_insn (gen_beq (label1)); emit_jump_insn (gen_beq (label1));
emit_insn (gen_rtx (SET, VOIDmode, dr, emit_insn (gen_rtx_SET (VOIDmode, dr,
gen_rtx (LSHIFTRT, DImode, dr, gen_rtx_LSHIFTRT (DImode, dr,
GEN_INT (32)))); gen_rtx_CONST_INT (SImode, 32))));
emit_insn (gen_rtx (SET, VOIDmode, dr, gen_rtx (MOD, SImode, dr, sr))); emit_insn (gen_rtx_SET (VOIDmode, dr, gen_rtx_MOD (SImode, dr, sr)));
emit_jump_insn (gen_jump (label3)); emit_jump_insn (gen_jump (label3));
emit_label (label1); emit_label (label1);
emit_insn (gen_rtx (SET, VOIDmode, dr_0, const0_rtx)); emit_insn (gen_rtx_SET (VOIDmode, dr_0, const0_rtx));
emit_jump_insn (gen_jump (label3)); emit_jump_insn (gen_jump (label3));
emit_label (label2); emit_label (label2);
emit_insn (gen_rtx (SET, VOIDmode, dr_0, emit_insn (gen_rtx_SET (VOIDmode, dr_0,
gen_rtx (MINUS, SImode, dr_0, sr))); gen_rtx_MINUS (SImode, dr_0, sr)));
emit_label (label3); emit_label (label3);
} }
emit_insn (gen_rtx (SET, VOIDmode, operands[0], dr_0)); emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_0));
DONE; DONE;
}") }")
...@@ -2441,8 +2784,8 @@ check_label_emit (); ...@@ -2441,8 +2784,8 @@ check_label_emit ();
(define_insn "" (define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d") [(set (match_operand:DI 0 "register_operand" "=d")
(mod:DI (match_operand:DI 1 "register_operand" "0") (mod:SI (match_operand:DI 1 "register_operand" "0")
(match_operand:SI 2 "general_operand" "")))] (match_operand:SI 2 "general_operand" "dm")))]
"" ""
"* "*
{ {
...@@ -2454,7 +2797,9 @@ check_label_emit (); ...@@ -2454,7 +2797,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"D %0,%2\"; return \"D %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- And instructions. ;;- And instructions.
...@@ -2494,6 +2839,7 @@ check_label_emit (); ...@@ -2494,6 +2839,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* and sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2504,10 +2850,11 @@ check_label_emit (); ...@@ -2504,10 +2850,11 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"N %0,%2\"; return \"N %0,%2\";
} }
CC_STATUS_INIT;
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"NC %O0(4,%R0),%2\"; return \"NC %O0(4,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "andsi3" (define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
...@@ -2517,6 +2864,7 @@ check_label_emit (); ...@@ -2517,6 +2864,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* and sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2524,7 +2872,9 @@ check_label_emit (); ...@@ -2524,7 +2872,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"N %0,%2\"; return \"N %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; andhi3 instruction pattern(s). ; andhi3 instruction pattern(s).
...@@ -2538,6 +2888,7 @@ check_label_emit (); ...@@ -2538,6 +2888,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* and sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2545,10 +2896,12 @@ check_label_emit (); ...@@ -2545,10 +2896,12 @@ check_label_emit ();
} }
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
/* %K2 == sign extend operand to 32 bits so that CH works */
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (GET_CODE (operands[2]) == CONST_INT)
return \"N %0,%K2\";
return \"N %0,%2\"; return \"N %0,%2\";
} }
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
...@@ -2556,7 +2909,9 @@ check_label_emit (); ...@@ -2556,7 +2909,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"NC %O0(2,%R0),%2\"; return \"NC %O0(2,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "andhi3" (define_insn "andhi3"
[(set (match_operand:HI 0 "general_operand" "=d") [(set (match_operand:HI 0 "general_operand" "=d")
...@@ -2566,14 +2921,18 @@ check_label_emit (); ...@@ -2566,14 +2921,18 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* and sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
/* %K2 == sign extend operand to 32 bits so that CH works */
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"N %0,%2\"; return \"N %0,%K2\";
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"NR %0,%2\"; return \"NR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; andqi3 instruction pattern(s). ; andqi3 instruction pattern(s).
...@@ -2587,7 +2946,7 @@ check_label_emit (); ...@@ -2587,7 +2946,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* and sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2605,7 +2964,9 @@ check_label_emit (); ...@@ -2605,7 +2964,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"NC %O0(1,%R0),%2\"; return \"NC %O0(1,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "andqi3" (define_insn "andqi3"
[(set (match_operand:QI 0 "general_operand" "=d") [(set (match_operand:QI 0 "general_operand" "=d")
...@@ -2615,7 +2976,7 @@ check_label_emit (); ...@@ -2615,7 +2976,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* and sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
...@@ -2623,7 +2984,9 @@ check_label_emit (); ...@@ -2623,7 +2984,9 @@ check_label_emit ();
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"NR %0,%2\"; return \"NR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Bit set (inclusive or) instructions. ;;- Bit set (inclusive or) instructions.
...@@ -2663,6 +3026,7 @@ check_label_emit (); ...@@ -2663,6 +3026,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2673,10 +3037,11 @@ check_label_emit (); ...@@ -2673,10 +3037,11 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"O %0,%2\"; return \"O %0,%2\";
} }
CC_STATUS_INIT;
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"OC %O0(4,%R0),%2\"; return \"OC %O0(4,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "iorsi3" (define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
...@@ -2686,6 +3051,7 @@ check_label_emit (); ...@@ -2686,6 +3051,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2693,7 +3059,9 @@ check_label_emit (); ...@@ -2693,7 +3059,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"O %0,%2\"; return \"O %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; iorhi3 instruction pattern(s). ; iorhi3 instruction pattern(s).
...@@ -2707,6 +3075,7 @@ check_label_emit (); ...@@ -2707,6 +3075,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2717,7 +3086,6 @@ check_label_emit (); ...@@ -2717,7 +3086,6 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"O %0,%2\"; return \"O %0,%2\";
} }
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
...@@ -2725,7 +3093,9 @@ check_label_emit (); ...@@ -2725,7 +3093,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"OC %O0(2,%R0),%2\"; return \"OC %O0(2,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "iorhi3" (define_insn "iorhi3"
[(set (match_operand:HI 0 "general_operand" "=d") [(set (match_operand:HI 0 "general_operand" "=d")
...@@ -2735,6 +3105,7 @@ check_label_emit (); ...@@ -2735,6 +3105,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
...@@ -2742,7 +3113,9 @@ check_label_emit (); ...@@ -2742,7 +3113,9 @@ check_label_emit ();
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"OR %0,%2\"; return \"OR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; iorqi3 instruction pattern(s). ; iorqi3 instruction pattern(s).
...@@ -2756,7 +3129,7 @@ check_label_emit (); ...@@ -2756,7 +3129,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2767,7 +3140,6 @@ check_label_emit (); ...@@ -2767,7 +3140,6 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"O %0,%2\"; return \"O %0,%2\";
} }
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
...@@ -2775,7 +3147,9 @@ check_label_emit (); ...@@ -2775,7 +3147,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"OC %O0(1,%R0),%2\"; return \"OC %O0(1,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "iorqi3" (define_insn "iorqi3"
[(set (match_operand:QI 0 "general_operand" "=d") [(set (match_operand:QI 0 "general_operand" "=d")
...@@ -2785,7 +3159,7 @@ check_label_emit (); ...@@ -2785,7 +3159,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* OR sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
...@@ -2793,7 +3167,9 @@ check_label_emit (); ...@@ -2793,7 +3167,9 @@ check_label_emit ();
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"OR %0,%2\"; return \"OR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Xor instructions. ;;- Xor instructions.
...@@ -2833,6 +3209,7 @@ check_label_emit (); ...@@ -2833,6 +3209,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2843,10 +3220,11 @@ check_label_emit (); ...@@ -2843,10 +3220,11 @@ check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"X %0,%2\"; return \"X %0,%2\";
} }
CC_STATUS_INIT;
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"XC %O0(4,%R0),%2\"; return \"XC %O0(4,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "xorsi3" (define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
...@@ -2856,6 +3234,7 @@ check_label_emit (); ...@@ -2856,6 +3234,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2863,7 +3242,9 @@ check_label_emit (); ...@@ -2863,7 +3242,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"X %0,%2\"; return \"X %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; xorhi3 instruction pattern(s). ; xorhi3 instruction pattern(s).
...@@ -2877,6 +3258,7 @@ check_label_emit (); ...@@ -2877,6 +3258,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2885,9 +3267,8 @@ check_label_emit (); ...@@ -2885,9 +3267,8 @@ check_label_emit ();
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"X %0,%2\"; return \"X %0,%H2\";
} }
CC_STATUS_INIT;
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
...@@ -2895,7 +3276,9 @@ check_label_emit (); ...@@ -2895,7 +3276,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"XC %O0(2,%R0),%2\"; return \"XC %O0(2,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "xorhi3" (define_insn "xorhi3"
[(set (match_operand:HI 0 "general_operand" "=d") [(set (match_operand:HI 0 "general_operand" "=d")
...@@ -2905,14 +3288,17 @@ check_label_emit (); ...@@ -2905,14 +3288,17 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"X %0,%2\"; return \"X %0,%H2\";
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"XR %0,%2\"; return \"XR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; xorqi3 instruction pattern(s). ; xorqi3 instruction pattern(s).
...@@ -2926,7 +3312,7 @@ check_label_emit (); ...@@ -2926,7 +3312,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
...@@ -2944,7 +3330,9 @@ check_label_emit (); ...@@ -2944,7 +3330,9 @@ check_label_emit ();
} }
mvs_check_page (0, 6, 0); mvs_check_page (0, 6, 0);
return \"XC %O0(1,%R0),%2\"; return \"XC %O0(1,%R0),%2\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "xorqi3" (define_insn "xorqi3"
[(set (match_operand:QI 0 "general_operand" "=d") [(set (match_operand:QI 0 "general_operand" "=d")
...@@ -2954,7 +3342,7 @@ check_label_emit (); ...@@ -2954,7 +3342,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
{ {
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
...@@ -2962,7 +3350,9 @@ check_label_emit (); ...@@ -2962,7 +3350,9 @@ check_label_emit ();
} }
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"XR %0,%2\"; return \"XR %0,%2\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Negate instructions. ;;- Negate instructions.
...@@ -2981,7 +3371,9 @@ check_label_emit (); ...@@ -2981,7 +3371,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LCR %0,%1\"; return \"LCR %0,%1\";
}") }"
[(set_attr "length" "2")]
)
; ;
; neghi2 instruction pattern(s). ; neghi2 instruction pattern(s).
...@@ -2996,7 +3388,9 @@ check_label_emit (); ...@@ -2996,7 +3388,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 10, 0); mvs_check_page (0, 10, 0);
return \"SLL %1,16\;SRA %1,16\;LCR %0,%1\"; return \"SLL %1,16\;SRA %1,16\;LCR %0,%1\";
}") }"
[(set_attr "length" "10")]
)
; ;
; negdf2 instruction pattern(s). ; negdf2 instruction pattern(s).
...@@ -3011,7 +3405,9 @@ check_label_emit (); ...@@ -3011,7 +3405,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LCDR %0,%1\"; return \"LCDR %0,%1\";
}") }"
[(set_attr "length" "2")]
)
; ;
; negsf2 instruction pattern(s). ; negsf2 instruction pattern(s).
...@@ -3026,7 +3422,9 @@ check_label_emit (); ...@@ -3026,7 +3422,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LCER %0,%1\"; return \"LCER %0,%1\";
}") }"
[(set_attr "length" "2")]
)
;; ;;
;;- Absolute value instructions. ;;- Absolute value instructions.
...@@ -3045,7 +3443,9 @@ check_label_emit (); ...@@ -3045,7 +3443,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LPR %0,%1\"; return \"LPR %0,%1\";
}") }"
[(set_attr "length" "2")]
)
; ;
; abshi2 instruction pattern(s). ; abshi2 instruction pattern(s).
...@@ -3060,7 +3460,9 @@ check_label_emit (); ...@@ -3060,7 +3460,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 10, 0); mvs_check_page (0, 10, 0);
return \"SLL %1,16\;SRA %1,16\;LPR %0,%1\"; return \"SLL %1,16\;SRA %1,16\;LPR %0,%1\";
}") }"
[(set_attr "length" "10")]
)
; ;
; absdf2 instruction pattern(s). ; absdf2 instruction pattern(s).
...@@ -3075,7 +3477,9 @@ check_label_emit (); ...@@ -3075,7 +3477,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LPDR %0,%1\"; return \"LPDR %0,%1\";
}") }"
[(set_attr "length" "2")]
)
; ;
; abssf2 instruction pattern(s). ; abssf2 instruction pattern(s).
...@@ -3090,7 +3494,9 @@ check_label_emit (); ...@@ -3090,7 +3494,9 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LPER %0,%1\"; return \"LPER %0,%1\";
}") }"
[(set_attr "length" "2")]
)
;; ;;
;;- One complement instructions. ;;- One complement instructions.
...@@ -3126,6 +3532,7 @@ check_label_emit (); ...@@ -3126,6 +3532,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
...@@ -3134,7 +3541,9 @@ check_label_emit (); ...@@ -3134,7 +3541,9 @@ check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT;
mvs_check_page (0, 6, 4); mvs_check_page (0, 6, 4);
return \"XC %O0(4,%R0),=F'-1'\"; return \"XC %O0(4,%R0),=F'-1'\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "one_cmplsi2" (define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=d") [(set (match_operand:SI 0 "general_operand" "=d")
...@@ -3143,9 +3552,12 @@ check_label_emit (); ...@@ -3143,9 +3552,12 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"X %0,=F'-1'\"; return \"X %0,=F'-1'\";
}") }"
[(set_attr "length" "4")]
)
; ;
; one_cmplhi2 instruction pattern(s). ; one_cmplhi2 instruction pattern(s).
...@@ -3158,15 +3570,17 @@ check_label_emit (); ...@@ -3158,15 +3570,17 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"X %0,=F'-1'\"; return \"X %0,=F'-1'\";
} }
CC_STATUS_INIT;
mvs_check_page (0, 6, 4); mvs_check_page (0, 6, 4);
return \"XC %O0(2,%R0),=X'FFFF'\"; return \"XC %O0(2,%R0),=X'FFFF'\";
}") }"
[(set_attr "length" "6")]
)
(define_insn "one_cmplhi2" (define_insn "one_cmplhi2"
[(set (match_operand:HI 0 "general_operand" "=d") [(set (match_operand:HI 0 "general_operand" "=d")
...@@ -3175,9 +3589,12 @@ check_label_emit (); ...@@ -3175,9 +3589,12 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* XOR sets CC but not how we want it */
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"X %0,=F'-1'\"; return \"X %0,=F'-1'\";
}") }"
[(set_attr "length" "4")]
)
; ;
; one_cmplqi2 instruction pattern(s). ; one_cmplqi2 instruction pattern(s).
...@@ -3190,7 +3607,7 @@ check_label_emit (); ...@@ -3190,7 +3607,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* XOR sets CC but not how we want it */
if (REG_P (operands[0])) if (REG_P (operands[0]))
{ {
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
...@@ -3198,7 +3615,9 @@ check_label_emit (); ...@@ -3198,7 +3615,9 @@ check_label_emit ();
} }
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
return \"XI %0,255\"; return \"XI %0,255\";
}") }"
[(set_attr "length" "4")]
)
(define_insn "one_cmplqi2" (define_insn "one_cmplqi2"
[(set (match_operand:QI 0 "general_operand" "=d") [(set (match_operand:QI 0 "general_operand" "=d")
...@@ -3207,10 +3626,12 @@ check_label_emit (); ...@@ -3207,10 +3626,12 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* XOR sets CC but not how we want it */
mvs_check_page (0, 4, 4); mvs_check_page (0, 4, 4);
return \"X %0,=F'-1'\"; return \"X %0,=F'-1'\";
}") }"
[(set_attr "length" "4")]
)
;; ;;
;;- Arithmetic shift instructions. ;;- Arithmetic shift instructions.
...@@ -3228,12 +3649,16 @@ check_label_emit (); ...@@ -3228,12 +3649,16 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; /* this status set seems not have the desired effect,
* proably because the 64-bit long-long test is emulated ?! */
CC_STATUS_SET (operands[0], operands[1]);
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLDA %0,0(%2)\"; return \"SLDA %0,0(%2)\";
return \"SLDA %0,%c2\"; return \"SLDA %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; ashrdi3 instruction pattern(s). ; ashrdi3 instruction pattern(s).
...@@ -3247,11 +3672,16 @@ check_label_emit (); ...@@ -3247,11 +3672,16 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
/* this status set seems not have the desired effect,
* proably because the 64-bit long-long test is emulated ?! */
CC_STATUS_SET (operands[0], operands[1]);
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SRDA %0,0(%2)\"; return \"SRDA %0,0(%2)\";
return \"SRDA %0,%c2\"; return \"SRDA %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; ashlsi3 instruction pattern(s). ; ashlsi3 instruction pattern(s).
...@@ -3265,12 +3695,13 @@ check_label_emit (); ...@@ -3265,12 +3695,13 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLL %0,0(%2)\"; return \"SLL %0,0(%2)\";
return \"SLL %0,%c2\"; return \"SLL %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; ashrsi3 instruction pattern(s). ; ashrsi3 instruction pattern(s).
...@@ -3284,11 +3715,14 @@ check_label_emit (); ...@@ -3284,11 +3715,14 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_SET (operands[0], operands[1]);
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SRA %0,0(%2)\"; return \"SRA %0,0(%2)\";
return \"SRA %0,%c2\"; return \"SRA %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; ashlhi3 instruction pattern(s). ; ashlhi3 instruction pattern(s).
...@@ -3306,7 +3740,9 @@ check_label_emit (); ...@@ -3306,7 +3740,9 @@ check_label_emit ();
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLL %0,16(%2)\;SRA %0,16\"; return \"SLL %0,16(%2)\;SRA %0,16\";
return \"SLL %0,16+%c2\;SRA %0,16\"; return \"SLL %0,16+%c2\;SRA %0,16\";
}") }"
[(set_attr "length" "8")]
)
; ;
; ashrhi3 instruction pattern(s). ; ashrhi3 instruction pattern(s).
...@@ -3320,11 +3756,13 @@ check_label_emit (); ...@@ -3320,11 +3756,13 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
mvs_check_page (0, 4, 0); mvs_check_page (0, 8, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLL %0,16\;SRA %0,16(%2)\"; return \"SLL %0,16\;SRA %0,16(%2)\";
return \"SLL %0,16\;SRA %0,16+%c2\"; return \"SLL %0,16\;SRA %0,16+%c2\";
}") }"
[(set_attr "length" "8")]
)
; ;
; ashlqi3 instruction pattern(s). ; ashlqi3 instruction pattern(s).
...@@ -3338,12 +3776,13 @@ check_label_emit (); ...@@ -3338,12 +3776,13 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT;
mvs_check_page (0, 4, 0); mvs_check_page (0, 4, 0);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLL %0,0(%2)\"; return \"SLL %0,0(%2)\";
return \"SLL %0,%c2\"; return \"SLL %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; ashrqi3 instruction pattern(s). ; ashrqi3 instruction pattern(s).
...@@ -3361,7 +3800,9 @@ check_label_emit (); ...@@ -3361,7 +3800,9 @@ check_label_emit ();
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SLL %0,24\;SRA %0,24(%2)\"; return \"SLL %0,24\;SRA %0,24(%2)\";
return \"SLL %0,24\;SRA %0,24+%c2\"; return \"SLL %0,24\;SRA %0,24+%c2\";
}") }"
[(set_attr "length" "8")]
)
;; ;;
;;- Logical shift instructions. ;;- Logical shift instructions.
...@@ -3383,7 +3824,9 @@ check_label_emit (); ...@@ -3383,7 +3824,9 @@ check_label_emit ();
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SRDL %0,0(%2)\"; return \"SRDL %0,0(%2)\";
return \"SRDL %0,%c2\"; return \"SRDL %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
...@@ -3402,7 +3845,9 @@ check_label_emit (); ...@@ -3402,7 +3845,9 @@ check_label_emit ();
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"SRL %0,0(%2)\"; return \"SRL %0,0(%2)\";
return \"SRL %0,%c2\"; return \"SRL %0,%c2\";
}") }"
[(set_attr "length" "4")]
)
; ;
; lshrhi3 instruction pattern(s). ; lshrhi3 instruction pattern(s).
...@@ -3416,7 +3861,7 @@ check_label_emit (); ...@@ -3416,7 +3861,7 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* AND sets the CC but not how we want it */
if (REG_P (operands[2])) if (REG_P (operands[2]))
{ {
mvs_check_page (0, 8, 4); mvs_check_page (0, 8, 4);
...@@ -3424,7 +3869,9 @@ check_label_emit (); ...@@ -3424,7 +3869,9 @@ check_label_emit ();
} }
mvs_check_page (0, 8, 4); mvs_check_page (0, 8, 4);
return \"N %0,=X'0000FFFF'\;SRL %0,%c2\"; return \"N %0,=X'0000FFFF'\;SRL %0,%c2\";
}") }"
[(set_attr "length" "8")]
)
; ;
; lshrqi3 instruction pattern(s). ; lshrqi3 instruction pattern(s).
...@@ -3438,16 +3885,18 @@ check_label_emit (); ...@@ -3438,16 +3885,18 @@ check_label_emit ();
"* "*
{ {
check_label_emit (); check_label_emit ();
CC_STATUS_INIT; CC_STATUS_INIT; /* AND sets the CC but not how we want it */
mvs_check_page (0, 8, 4); mvs_check_page (0, 8, 4);
if (REG_P (operands[2])) if (REG_P (operands[2]))
return \"N %0,=X'000000FF'\;SRL %0,0(%2)\"; return \"N %0,=X'000000FF'\;SRL %0,0(%2)\";
return \"N %0,=X'000000FF'\;SRL %0,%c2\"; return \"N %0,=X'000000FF'\;SRL %0,%c2\";
}") }"
[(set_attr "length" "8")]
)
;; ;; =======================================================================
;;- Conditional jump instructions. ;;- Conditional jump instructions.
;; ;; =======================================================================
; ;
; beq instruction pattern(s). ; beq instruction pattern(s).
...@@ -3458,23 +3907,23 @@ check_label_emit (); ...@@ -3458,23 +3907,23 @@ check_label_emit ();
(if_then_else (eq (cc0) (if_then_else (eq (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BE %l0\";
return \"L 14,=A(%l0)\;BER 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BER 14\"; return \"L 14,=A(%l0)\;BER 14\";
} }"
return \"BE %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bne instruction pattern(s). ; bne instruction pattern(s).
...@@ -3485,23 +3934,23 @@ check_label_emit (); ...@@ -3485,23 +3934,23 @@ check_label_emit ();
(if_then_else (ne (cc0) (if_then_else (ne (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNE %l0\";
return \"L 14,=A(%l0)\;BNER 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNER 14\"; return \"L 14,=A(%l0)\;BNER 14\";
} }"
return \"BNE %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bgt instruction pattern(s). ; bgt instruction pattern(s).
...@@ -3512,23 +3961,23 @@ check_label_emit (); ...@@ -3512,23 +3961,23 @@ check_label_emit ();
(if_then_else (gt (cc0) (if_then_else (gt (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BH %l0\";
return \"L 14,=A(%l0)\;BHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BHR 14\"; return \"L 14,=A(%l0)\;BHR 14\";
} }"
return \"BH %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bgtu instruction pattern(s). ; bgtu instruction pattern(s).
...@@ -3539,23 +3988,23 @@ check_label_emit (); ...@@ -3539,23 +3988,23 @@ check_label_emit ();
(if_then_else (gtu (cc0) (if_then_else (gtu (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BH %l0\";
return \"L 14,=A(%l0)\;BHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BHR 14\"; return \"L 14,=A(%l0)\;BHR 14\";
} }"
return \"BH %l0\"; [(set_attr "length" "6")]
}") )
; ;
; blt instruction pattern(s). ; blt instruction pattern(s).
...@@ -3566,23 +4015,23 @@ check_label_emit (); ...@@ -3566,23 +4015,23 @@ check_label_emit ();
(if_then_else (lt (cc0) (if_then_else (lt (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BL %l0\";
return \"L 14,=A(%l0)\;BLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BLR 14\"; return \"L 14,=A(%l0)\;BLR 14\";
} }"
return \"BL %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bltu instruction pattern(s). ; bltu instruction pattern(s).
...@@ -3593,23 +4042,23 @@ check_label_emit (); ...@@ -3593,23 +4042,23 @@ check_label_emit ();
(if_then_else (ltu (cc0) (if_then_else (ltu (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BL %l0\";
return \"L 14,=A(%l0)\;BLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BLR 14\"; return \"L 14,=A(%l0)\;BLR 14\";
} }"
return \"BL %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bge instruction pattern(s). ; bge instruction pattern(s).
...@@ -3620,23 +4069,23 @@ check_label_emit (); ...@@ -3620,23 +4069,23 @@ check_label_emit ();
(if_then_else (ge (cc0) (if_then_else (ge (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNL %l0\";
return \"L 14,=A(%l0)\;BNLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNLR 14\"; return \"L 14,=A(%l0)\;BNLR 14\";
} }"
return \"BNL %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bgeu instruction pattern(s). ; bgeu instruction pattern(s).
...@@ -3647,23 +4096,23 @@ check_label_emit (); ...@@ -3647,23 +4096,23 @@ check_label_emit ();
(if_then_else (geu (cc0) (if_then_else (geu (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNL %l0\";
return \"L 14,=A(%l0)\;BNLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNLR 14\"; return \"L 14,=A(%l0)\;BNLR 14\";
} }"
return \"BNL %l0\"; [(set_attr "length" "6")]
}") )
; ;
; ble instruction pattern(s). ; ble instruction pattern(s).
...@@ -3674,23 +4123,23 @@ check_label_emit (); ...@@ -3674,23 +4123,23 @@ check_label_emit ();
(if_then_else (le (cc0) (if_then_else (le (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNH %l0\";
return \"L 14,=A(%l0)\;BNHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNHR 14\"; return \"L 14,=A(%l0)\;BNHR 14\";
} }"
return \"BNH %l0\"; [(set_attr "length" "6")]
}") )
; ;
; bleu instruction pattern(s). ; bleu instruction pattern(s).
...@@ -3701,23 +4150,23 @@ check_label_emit (); ...@@ -3701,23 +4150,23 @@ check_label_emit ();
(if_then_else (leu (cc0) (if_then_else (leu (cc0)
(const_int 0)) (const_int 0))
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNH %l0\";
return \"L 14,=A(%l0)\;BNHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNHR 14\"; return \"L 14,=A(%l0)\;BNHR 14\";
} }"
return \"BNH %l0\"; [(set_attr "length" "6")]
}") )
;; ;;
;;- Negated conditional jump instructions. ;;- Negated conditional jump instructions.
...@@ -3728,234 +4177,235 @@ check_label_emit (); ...@@ -3728,234 +4177,235 @@ check_label_emit ();
(if_then_else (eq (cc0) (if_then_else (eq (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNE %l0\";
return \"L 14,=A(%l0)\;BNER 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNER 14\"; return \"L 14,=A(%l0)\;BNER 14\";
} }"
return \"BNE %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (ne (cc0) (if_then_else (ne (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BE %l0\";
return \"L 14,=A(%l0)\;BER 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BER 14\"; return \"L 14,=A(%l0)\;BER 14\";
} }"
return \"BE %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (gt (cc0) (if_then_else (gt (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNH %l0\";
return \"L 14,=A(%l0)\;BNHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNHR 14\"; return \"L 14,=A(%l0)\;BNHR 14\";
} }"
return \"BNH %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (gtu (cc0) (if_then_else (gtu (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNH %l0\";
return \"L 14,=A(%l0)\;BNHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNHR 14\"; return \"L 14,=A(%l0)\;BNHR 14\";
} }"
return \"BNH %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (lt (cc0) (if_then_else (lt (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNL %l0\";
return \"L 14,=A(%l0)\;BNLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNLR 14\"; return \"L 14,=A(%l0)\;BNLR 14\";
} }"
return \"BNL %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (ltu (cc0) (if_then_else (ltu (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BNL %l0\";
return \"L 14,=A(%l0)\;BNLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BNLR 14\"; return \"L 14,=A(%l0)\;BNLR 14\";
} }"
return \"BNL %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (ge (cc0) (if_then_else (ge (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BL %l0\";
return \"L 14,=A(%l0)\;BLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BLR 14\"; return \"L 14,=A(%l0)\;BLR 14\";
} }"
return \"BL %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (geu (cc0) (if_then_else (geu (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BL %l0\";
return \"L 14,=A(%l0)\;BLR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BLR 14\"; return \"L 14,=A(%l0)\;BLR 14\";
} }"
return \"BL %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (le (cc0) (if_then_else (le (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BH %l0\";
return \"L 14,=A(%l0)\;BHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BHR 14\"; return \"L 14,=A(%l0)\;BHR 14\";
} }"
return \"BH %l0\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
(if_then_else (leu (cc0) (if_then_else (leu (cc0)
(const_int 0)) (const_int 0))
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"BH %l0\";
return \"L 14,=A(%l0)\;BHR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BHR 14\"; return \"L 14,=A(%l0)\;BHR 14\";
} }"
return \"BH %l0\"; [(set_attr "length" "6")]
}") )
;; ;; ==============================================================
;;- Subtract one and jump if not zero. ;;- Subtract one and jump if not zero.
;; ;; These insns seem to not be getting matched ...
;; XXX should fix this, as it would improve for loops
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
...@@ -3967,23 +4417,23 @@ check_label_emit (); ...@@ -3967,23 +4417,23 @@ check_label_emit ();
(pc))) (pc)))
(set (match_dup 0) (set (match_dup 0)
(plus:SI (match_dup 0) (plus:SI (match_dup 0)
(const_int -1)))] (const_int -1)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[1]))) mvs_check_page (0, 4, 0);
if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
{ {
mvs_check_page (0, 6, 4); return \"BCT %0,%l1\";
return \"L 14,=A(%l1)\;BCTR %0,14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l1)\;BCTR %0,14\"; return \"L 14,=A(%l1)\;BCTR %0,14\";
} }"
return \"BCT %0,%l1\"; [(set_attr "length" "6")]
}") )
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
...@@ -3995,25 +4445,25 @@ check_label_emit (); ...@@ -3995,25 +4445,25 @@ check_label_emit ();
(label_ref (match_operand 1 "" "")))) (label_ref (match_operand 1 "" ""))))
(set (match_dup 0) (set (match_dup 0)
(plus:SI (match_dup 0) (plus:SI (match_dup 0)
(const_int -1)))] (const_int -1)))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[1]))) mvs_check_page (0, 4, 0);
if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
{ {
mvs_check_page (0, 6, 4); return \"BCT %0,%l1\";
return \"L 14,=A(%l1)\;BCTR %0,14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l1)\;BCTR %0,14\"; return \"L 14,=A(%l1)\;BCTR %0,14\";
} }"
return \"BCT %0,%l1\"; [(set_attr "length" "6")]
}") )
;; ;; =============================================================
;;- Unconditional jump instructions. ;;- Unconditional jump instructions.
;; ;;
...@@ -4023,37 +4473,44 @@ check_label_emit (); ...@@ -4023,37 +4473,44 @@ check_label_emit ();
(define_insn "jump" (define_insn "jump"
[(set (pc) [(set (pc)
(label_ref (match_operand 0 "" "")))] (label_ref (match_operand 0 "" "")))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0]))) mvs_check_page (0, 4, 0);
if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
{ {
mvs_check_page (0, 6, 4); return \"B %l0\";
return \"L 14,=A(%l0)\;BR 14\";
} }
if (mvs_check_page (0, 4, 0))
{
mvs_check_page (0, 2, 4); mvs_check_page (0, 2, 4);
return \"L 14,=A(%l0)\;BR 14\"; return \"L 14,=A(%l0)\;BR 14\";
} }"
return \"B %l0\"; [(set_attr "length" "6")]
}") )
; ;
; indirect-jump instruction pattern(s). ; indirect-jump instruction pattern(s).
; ; hack alert -- should check that displacement is < 4096
(define_insn "indirect_jump" (define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "general_operand" "r"))] [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
"(GET_CODE (operands[0]) != MEM )" ""
"* "*
{ {
check_label_emit (); check_label_emit ();
if (REG_P (operands[0]))
{
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"BR %0\"; return \"BR %0\";
}") }
mvs_check_page (0, 4, 0);
return \"B %0\";
}"
[(set_attr "length" "4")]
)
; ;
; tablejump instruction pattern(s). ; tablejump instruction pattern(s).
...@@ -4062,7 +4519,9 @@ check_label_emit (); ...@@ -4062,7 +4519,9 @@ check_label_emit ();
(define_insn "tablejump" (define_insn "tablejump"
[(set (pc) [(set (pc)
(match_operand:SI 0 "general_operand" "am")) (match_operand:SI 0 "general_operand" "am"))
(use (label_ref (match_operand 1 "" "")))] (use (label_ref (match_operand 1 "" "")))
; (clobber (reg:SI 14))
]
"" ""
"* "*
{ {
...@@ -4074,7 +4533,9 @@ check_label_emit (); ...@@ -4074,7 +4533,9 @@ check_label_emit ();
} }
mvs_check_page (0, 10, 0); mvs_check_page (0, 10, 0);
return \"L 14,%0\;BR 14\;DS 0F\"; return \"L 14,%0\;BR 14\;DS 0F\";
}") }"
[(set_attr "length" "10")]
)
;; ;;
;;- Jump to subroutine. ;;- Jump to subroutine.
...@@ -4082,34 +4543,55 @@ check_label_emit (); ...@@ -4082,34 +4543,55 @@ check_label_emit ();
;; For the C/370 environment the internal functions, ie. sqrt, are called with ;; For the C/370 environment the internal functions, ie. sqrt, are called with
;; a non-standard form. So, we must fix it here. There's no BM like IBM. ;; a non-standard form. So, we must fix it here. There's no BM like IBM.
;; ;;
;; The ELF ABI is different from the C/370 ABI because we have a simpler,
;; more powerful way of dealing with structure-value returns. Basically,
;; we use R1 to point at structure returns (64-bit and larger returns)
;; and R11 to point at the args. Note that this handles double-precision
;; (64-bit) values just fine, in a less-kludged manner than the C/370 ABI.
;; Since R1 is used, we use R2 to pass the argument pointer to the routine.
; ;
; call instruction pattern(s). ; call instruction pattern(s).
; ;
; We define four call instruction patterns below. The first two patterns,
; although general, end up matching (only?) calls through function pointers.
; The last two, which require a symbol-ref to match, get used for all
; ordinary subroutine calls.
(define_insn "call" (define_insn "call"
[(call (match_operand:QI 0 "memory_operand" "m") [(call (match_operand:QI 0 "memory_operand" "m")
(match_operand:SI 1 "immediate_operand" "i"))] (match_operand:SI 1 "immediate_operand" "i"))
(clobber (reg:SI 2))
]
"" ""
"* "*
{ {
static char temp[128]; static char temp[128];
int i = STACK_POINTER_OFFSET; int i = STACK_POINTER_OFFSET;
CC_STATUS_INIT;
check_label_emit (); check_label_emit ();
#ifdef TARGET_ELF_ABI
mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA r2,%d(,sp)\;LA 15,%%0\;BASR 14,15\", i );
return temp;
#else
if (mvs_function_check (XSTR (operands[0], 0))) if (mvs_function_check (XSTR (operands[0], 0)))
{ {
mvs_check_page (0, 22, 4); mvs_check_page (0, 22, 4);
sprintf ( temp, \"LA 1,136(,13)\;ST 1,%d(,13)\;LA 1,%d(,13)\;L 15,%%0\;BALR 14,15\;LD 0,136(,13)\", sprintf ( temp, \"LA 1,136(,13)\;ST 1,%d(,13)\;LA 1,%d(,13)\;LA 15,%%0\;BALR 14,15\;LD 0,136(,13)\",
i - 4, i - 4 ); i - 4, i - 4 );
} }
else else
{ {
mvs_check_page (0, 10, 4); mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%0\;BALR 14,15\", i ); sprintf ( temp, \"LA 1,%d(,13)\;LA 15,%%0\;BALR 14,15\", i );
} }
return temp; return temp;
}") #endif
}"
[(set_attr "length" "22")]
)
; ;
; call_value instruction pattern(s). ; call_value instruction pattern(s).
...@@ -4118,38 +4600,57 @@ check_label_emit (); ...@@ -4118,38 +4600,57 @@ check_label_emit ();
(define_insn "call_value" (define_insn "call_value"
[(set (match_operand 0 "" "rf") [(set (match_operand 0 "" "rf")
(call (match_operand:QI 1 "memory_operand" "m") (call (match_operand:QI 1 "memory_operand" "m")
(match_operand:SI 2 "general_operand" "i")))] (match_operand:SI 2 "general_operand" "i")))
(clobber (reg:SI 2))
]
"" ""
"* "*
{ {
static char temp[128]; static char temp[128];
int i = STACK_POINTER_OFFSET; int i = STACK_POINTER_OFFSET;
CC_STATUS_INIT;
check_label_emit (); check_label_emit ();
#ifdef TARGET_ELF_ABI
mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA r2,%d(,sp)\;LA 15,%%1\;BASR 14,15\", i );
return temp;
#else
if (mvs_function_check (XSTR (operands[1], 0))) if (mvs_function_check (XSTR (operands[1], 0)))
{ {
mvs_check_page (0, 22, 4); mvs_check_page (0, 22, 4);
sprintf ( temp, \"LA 1,136(,13)\;ST 1,%d(,13)\;LA 1,%d(,13)\;L 15,%%1\;BALR 14,15\;LD 0,136(,13)\", sprintf ( temp, \"LA 1,136(,13)\;ST 1,%d(,13)\;LA 1,%d(,13)\;LA 15,%%1\;BALR 14,15\;LD 0,136(,13)\",
i - 4, i - 4 ); i - 4, i - 4 );
} }
else else
{ {
mvs_check_page (0, 10, 4); mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%1\;BALR 14,15\", i ); sprintf ( temp, \"LA 1,%d(,13)\;LA 15,%%1\;BALR 14,15\", i );
} }
return temp; return temp;
}") #endif
}"
[(set_attr "length" "22")]
)
(define_insn "" (define_insn ""
[(call (mem:QI (match_operand:SI 0 "" "i")) [(call (mem:QI (match_operand:SI 0 "" "i"))
(match_operand:SI 1 "general_operand" "g"))] (match_operand:SI 1 "general_operand" "g"))
(clobber (reg:SI 2))
]
"GET_CODE (operands[0]) == SYMBOL_REF" "GET_CODE (operands[0]) == SYMBOL_REF"
"* "*
{ {
static char temp[128]; static char temp[128];
int i = STACK_POINTER_OFFSET; int i = STACK_POINTER_OFFSET;
CC_STATUS_INIT;
check_label_emit (); check_label_emit ();
#ifdef TARGET_ELF_ABI
mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA r2,%d(,sp)\;L 15,%%0\;BASR 14,15\", i );
return temp;
#else
if (mvs_function_check (XSTR (operands[0], 0))) if (mvs_function_check (XSTR (operands[0], 0)))
{ {
mvs_check_page (0, 22, 4); mvs_check_page (0, 22, 4);
...@@ -4162,19 +4663,30 @@ check_label_emit (); ...@@ -4162,19 +4663,30 @@ check_label_emit ();
sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%0\;BALR 14,15\", i ); sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%0\;BALR 14,15\", i );
} }
return temp; return temp;
}") #endif
}"
[(set_attr "length" "22")]
)
(define_insn "" (define_insn ""
[(set (match_operand 0 "" "rf") [(set (match_operand 0 "" "rf")
(call (mem:QI (match_operand:SI 1 "" "i")) (call (mem:QI (match_operand:SI 1 "" "i"))
(match_operand:SI 2 "general_operand" "g")))] (match_operand:SI 2 "general_operand" "g")))
(clobber (reg:SI 2))
]
"GET_CODE (operands[1]) == SYMBOL_REF" "GET_CODE (operands[1]) == SYMBOL_REF"
"* "*
{ {
static char temp[128]; static char temp[128];
int i = STACK_POINTER_OFFSET; int i = STACK_POINTER_OFFSET;
CC_STATUS_INIT;
check_label_emit (); check_label_emit ();
#ifdef TARGET_ELF_ABI
mvs_check_page (0, 10, 4);
sprintf ( temp, \"LA r2,%d(,sp)\;L 15,%%1\;BASR 14,15\", i );
return temp;
#else
if (mvs_function_check (XSTR (operands[1], 0))) if (mvs_function_check (XSTR (operands[1], 0)))
{ {
mvs_check_page (0, 22, 4); mvs_check_page (0, 22, 4);
...@@ -4187,6 +4699,44 @@ check_label_emit (); ...@@ -4187,6 +4699,44 @@ check_label_emit ();
sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%1\;BALR 14,15\", i ); sprintf ( temp, \"LA 1,%d(,13)\;L 15,%%1\;BALR 14,15\", i );
} }
return temp; return temp;
#endif
}"
[(set_attr "length" "22")]
)
;;
;; Call subroutine returning any type.
;; This instruction pattern appears to be used only by the
;; expand_builtin_apply definition for __builtin_apply. It is needed
;; since call_value might return an in in r15 or a float in fpr0 (r16)
;; and the builtin code calla abort since the reg is ambiguous. Well,
;; the below is probably broken anyway, we just want to go for now.
;;
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
int i;
emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
claiming that all hard registers are used and clobbered at this
point. */
/* emit_insn (gen_blockage ()); */
DONE;
}") }")
...@@ -4206,5 +4756,6 @@ check_label_emit (); ...@@ -4206,5 +4756,6 @@ check_label_emit ();
check_label_emit (); check_label_emit ();
mvs_check_page (0, 2, 0); mvs_check_page (0, 2, 0);
return \"LR 0,0\"; return \"LR 0,0\";
}") }"
[(set_attr "length" "2")]
)
/* Definitions of target machine for GNU compiler. System/370 version.
Copyright (C) 1989, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for Linux/390 by Linas Vepstas (linas@linas.org)
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. */
#define TARGET_VERSION fprintf (stderr, " (i370 GNU/Linux with ELF)");
/* Specify that we're generating code for a Linux port to 370 */
#define TARGET_ELF_ABI
#define LINUX_DEFAULT_ELF
/* hack alert define to get dbx/gdb/dwarf to compile */
/* problem is that host float format is not target float format. */
/* define REAL_ARITHMETIC for software emulation of float to
* int conversion. This seems to have somethings to do with
* cross-compiling ... */
#define REAL_ARITHMETIC
/* Include system common definitions */
#include "config/linux.h"
#include "config/i370/i370.h"
/* Names to predefine in the preprocessor for this target machine. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-DGCC -Dgcc -D__ELF__ -Dunix -Dlinux -Asystem(posix) -Acpu(i370) -Amachine(i370)"
/* Options for this target machine. */
#define LIBGCC_SPEC "libgcc.a%s"
#ifdef SOME_FUTURE_DAY
#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %(cpp_sysv) %(cpp_endian_big) \
%{mcall-linux: %(cpp_os_linux) } \
%{!mcall-linux: %(cpp_os_default) }"
#define LIB_SPEC "\
%{mcall-linux: %(lib_linux) } \
%{!mcall-linux:%(lib_default) }"
#define STARTFILE_SPEC "\
%{mcall-linux: %(startfile_linux) } \
%{!mcall-linux: %(startfile_default) }"
#define ENDFILE_SPEC "\
%{mcall-linux: %(endfile_linux) } \
%{!mcall-linux: %(endfile_default) }"
/* GNU/Linux support. */
#ifndef LIB_LINUX_SPEC
#define LIB_LINUX_SPEC "%{mnewlib: --start-group -llinux -lc --end-group } %{!mnewlib: -lc }"
#endif
#ifndef STARTFILE_LINUX_SPEC
#define STARTFILE_LINUX_SPEC "\
%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}} \
%{mnewlib: ecrti.o%s} \
%{!mnewlib: crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}"
#endif
#ifndef ENDFILE_LINUX_SPEC
#define ENDFILE_LINUX_SPEC "\
%{mnewlib: ecrtn.o%s} \
%{!mnewlib: %{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s}"
#endif
#ifndef LINK_START_LINUX_SPEC
#define LINK_START_LINUX_SPEC "-Ttext 0x10000"
#endif
#ifndef LINK_OS_LINUX_SPEC
#define LINK_OS_LINUX_SPEC ""
#endif
#ifndef CPP_OS_LINUX_SPEC
#define CPP_OS_LINUX_SPEC "-D__unix__ -D__linux__ \
%{!ansi: -Dunix -Dlinux } \
-Asystem(unix) -Asystem(linux)"
#endif
#ifndef CPP_OS_LINUX_SPEC
#define CPP_OS_LINUX_SPEC ""
#endif
/* Define any extra SPECS that the compiler needs to generate. */
#undef SUBTARGET_EXTRA_SPECS
#define SUBTARGET_EXTRA_SPECS \
{ "lib_linux", LIB_LINUX_SPEC }, \
{ "lib_default", LIB_DEFAULT_SPEC }, \
{ "startfile_linux", STARTFILE_LINUX_SPEC }, \
{ "startfile_default", STARTFILE_DEFAULT_SPEC }, \
{ "endfile_linux", ENDFILE_LINUX_SPEC }, \
{ "endfile_default", ENDFILE_DEFAULT_SPEC }, \
{ "link_shlib", LINK_SHLIB_SPEC }, \
{ "link_target", LINK_TARGET_SPEC }, \
{ "link_start", LINK_START_SPEC }, \
{ "link_start_linux", LINK_START_LINUX_SPEC }, \
{ "link_os", LINK_OS_SPEC }, \
{ "link_os_linux", LINK_OS_LINUX_SPEC }, \
{ "link_os_default", LINK_OS_DEFAULT_SPEC }, \
{ "cpp_endian_big", CPP_ENDIAN_BIG_SPEC }, \
{ "cpp_os_linux", CPP_OS_LINUX_SPEC }, \
{ "cpp_os_default", CPP_OS_DEFAULT_SPEC },
#endif /* SOME_FUTURE_DAY */
/* Definitions of target machine for GNU compiler. System/370 version.
Copyright (C) 1989, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
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. */
#define TARGET_VERSION printf (" (370/MVS)");
/* Specify that we're generating code for the Language Environment */
#define LE370 1
#define TARGET_EBCDIC 1
#define TARGET_HLASM 1
/* Options for the preprocessor for this target machine. */
#define CPP_SPEC "-trigraphs"
/* Names to predefine in the preprocessor for this target machine. */
#if defined(LE370)
#define CPP_PREDEFINES "-DGCC -Dgcc -DMVS -Dmvs -DLE370 -Asystem(mvs) -Acpu(i370) -Amachine(i370)"
#else
#define CPP_PREDEFINES "-DGCC -Dgcc -DMVS -Dmvs -Asystem(mvs) -Acpu(i370) -Amachine(i370)"
#endif
/* Include system common definitions */
#include "config/i370/i370.h"
/* Definitions of target machine for GNU compiler. System/370 version.
Copyright (C) 1989, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for OS/390 OpenEdition by Dave Pitts (dpitts@cozx.com)
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. */
#define TARGET_VERSION printf (" (370/OpenEdition)");
/* Specify that we're generating code for the Language Environment */
#define LE370 1
#define LONGEXTERNAL 1
#define TARGET_EBCDIC 1
#define TARGET_HLASM 1
/* Options for this target machine. */
#define LIB_SPEC ""
#define LIBGCC_SPEC ""
#define STARTFILE_SPEC "/usr/local/lib/gccmain.o"
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-DGCC -Dgcc -DUNIX -Dunix -Dopenedition -D__i370__ -Asystem(openedition) -Asystem(unix) -Acpu(i370) -Amachine(i370)"
/* Include system common definitions */
#include "config/i370/i370.h"
# config/i370/t-linux: this file defines Makefile overrides when building
# for a Linux target. Thes definitions are in addition to config/t-linux.
# pretty busted at the moment
CROSS_LIBGCC1 =
# There is no libgcc for mvs
LIBGCC =
INSTALL_LIBGCC =
LIBGCC1_TEST =
# There is no libgcc for OpenEdition
LIBGCC =
INSTALL_LIBGCC =
LIBGCC1_TEST =
#
# Host is an i370 running OpenEdition
#
# Use GCC alloca
ALLOCA = alloca.o
# Don't bother fixing up header files, they're wierd
STMP_FIXPROTO =
# Set up to make using c89
X_CFLAGS=-D_ALL_SOURCE
CC=c89
# Explicitly use libiberty
CLIB=-liberty
LDFLAGS=-L../libiberty
# TAR Options
TAROUTOPTS=xpf
/* Configuration for GNU C-compiler for System/370.
Copyright (C) 1989, 1993, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for OS/390 OpenEdition by Dave Pitts (dpitts@cozx.com)
Modified for 390/Linux by Linas Vepstas (linas@linas.org)
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. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
#define USE_STDARGS 1
#define USE_PROTOTYPES 1
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_BITS_PER_LONGLONG 64
#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
#define HOST_WORDS_BIG_ENDIAN
/* If not compiled with GNU C, use the C alloca and use only int bitfields. */
#ifndef __GNUC__
#define USE_C_ALLOCA
#if __STDC__
extern void *alloca ();
#else
extern char *alloca ();
#endif
#define ONLY_INT_FIELDS
#endif
// #define USG
/* Target machine dependencies. tm.h is a symbolic link to the actual
target specific file. */
#include "tm.h"
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 12
// #define NO_DBX_FORMAT
/* Configuration for GNU C-compiler for System/370.
Copyright (C) 1989, 1993, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
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. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_FLOAT_FORMAT IBM_FLOAT_FORMAT
#define HOST_EBCDIC 1
#define USG
#ifndef MVS
#define MVS
#endif
/* Target machine dependencies. tm.h is a symbolic link to the actual
target specific file. */
#include "tm.h"
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 12
#define NO_DBX_FORMAT
/* Configuration for GNU C-compiler for System/370.
Copyright (C) 1989, 1993, 1997 Free Software Foundation, Inc.
Contributed by Jan Stein (jan@cd.chalmers.se).
Modified for OS/390 OpenEdition by Dave Pitts (dpitts@cozx.com)
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. */
/* #defines that need visibility everywhere. */
#define FALSE 0
#define TRUE 1
#define USE_STDARGS 1
#define USE_PROTOTYPES 1
/* This describes the machine the compiler is hosted on. */
#define HOST_BITS_PER_CHAR 8
#define HOST_BITS_PER_SHORT 16
#define HOST_BITS_PER_INT 32
#define HOST_BITS_PER_LONG 32
#define HOST_FLOAT_FORMAT IBM_FLOAT_FORMAT
#define HOST_EBCDIC 1
#define ONLY_INT_FIELDS 1
#define USG
/* Target machine dependencies. tm.h is a symbolic link to the actual
target specific file. */
#include "tm.h"
/* Arguments to use with `exit'. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 12
#define NO_DBX_FORMAT
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment