Bulk patch from Linas.
authorLinas Vepstas <linas@linas.org>
Mon, 19 Jul 1999 19:26:30 +0000 (19:26 +0000)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 19 Jul 1999 19:26:30 +0000 (12:26 -0700)
From-SVN: r28178

15 files changed:
gcc/ChangeLog
gcc/config/i370/README [new file with mode: 0644]
gcc/config/i370/i370.c
gcc/config/i370/i370.h
gcc/config/i370/i370.md
gcc/config/i370/linux.h [new file with mode: 0644]
gcc/config/i370/mvs.h [new file with mode: 0644]
gcc/config/i370/oe.h [new file with mode: 0644]
gcc/config/i370/t-linux [new file with mode: 0644]
gcc/config/i370/t-mvs [new file with mode: 0644]
gcc/config/i370/t-oe [new file with mode: 0644]
gcc/config/i370/x-oe [new file with mode: 0644]
gcc/config/i370/xm-linux.h [new file with mode: 0644]
gcc/config/i370/xm-mvs.h [new file with mode: 0644]
gcc/config/i370/xm-oe.h [new file with mode: 0644]

index dd689e275eb8b50c61cb5c7effd93cde949a79ef..6c8acf92706bb91185f6183fdbd7a84a785e2c4f 100644 (file)
@@ -1,3 +1,72 @@
+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>
 
        * rs6000.md (arithmetic, logical, and shift Rc combiner patterns):
diff --git a/gcc/config/i370/README b/gcc/config/i370/README
new file mode 100644 (file)
index 0000000..5bf99f5
--- /dev/null
@@ -0,0 +1,87 @@
+
+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
+
+
+
+
+
+
index 55189825540856198400ed8bb1c03be8c59b1ae1..8287c92e09fccb80ce068af899c3ff0f9779672e 100644 (file)
@@ -1,7 +1,8 @@
 /* Subroutines for insn-output.c for System/370.
    Copyright (C) 1989, 1993, 1995, 1997 Free Software Foundation, Inc.
    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.
 
@@ -24,7 +25,11 @@ Boston, MA 02111-1307, USA.  */
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>  
 #include "rtl.h"
+#include "tree.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
@@ -35,26 +40,34 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "flags.h"
 #include "recog.h"
-#ifdef sun
-#include <sys/types.h>
-#include <ctype.h>
-#endif
 #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
   {
     struct label_node *label_next;
     int label_id;
     int label_page;
+    int first_ref_page;
+
+    int label_addr;
+    int label_first_ref;
+    int label_last_ref;
   }
 label_node_t;
 
-/* Is 1 when a label has been generated and the base register must be
-   reloaded.  */
-int mvs_label_emitted = 0;
+/* Is 1 when a label has been generated and the base register must be reloaded.  */
+int mvs_need_base_reload = 0;
 
 /* Current function starting base page.  */
 int function_base_page;
@@ -83,6 +96,37 @@ static label_node_t *free_anchor = 0;
 /* Assembler source file descriptor.  */
 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 MVS_FUNCTION_TABLE_LENGTH 32
 
@@ -90,16 +134,27 @@ static FILE *assembler_source = 0;
    and must handled in a special manner.  */
 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",
    "edc_cosh", "edc_erf",  "edc_erfc", "edc_exp",  "edc_gamm", "edc_lg10",
    "edc_log",  "edc_sin",  "edc_sinh", "edc_sqrt", "edc_tan",  "edc_tanh",
    "fabs",     "floor",    "fmod",     "frexp",    "hypot",    "j0",
    "j1",       "jn",       "ldexp",    "modf",     "pow",      "y0",
    "y1",       "yn"
+#endif
 };
 
+#endif /* TARGET_HLASM */
+/* ===================================================== */
+
 /* ASCII to EBCDIC conversion table.  */
-#if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
 static unsigned char ascebc[256] =
 {
  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
@@ -151,10 +206,8 @@ static unsigned char ascebc[256] =
      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
 };
-#endif
 
 /* EBCDIC to ASCII conversion table.  */
-#if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
 unsigned char ebcasc[256] =
 {
  /*00  NU    SH    SX    EX    PF    HT    LC    DL */
@@ -222,7 +275,6 @@ unsigned char ebcasc[256] =
  /*F8   8     9                                     */
      0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
 };
-#endif
 
 /* Map characters from one character set to another.
    C is the character to be translated.  */
@@ -232,26 +284,278 @@ mvs_map_char (c)
      char c;
 {
 #if defined(TARGET_EBCDIC) && !defined(HOST_EBCDIC)
+  fprintf (stderr, "mvs_map_char: TE & !HE: c = %02x\n", c);
   return ascebc[c];
 #else
 #if defined(HOST_EBCDIC) && !defined(TARGET_EBCDIC)
+  fprintf (stderr, "mvs_map_char: !TE & HE: c = %02x\n", c);
   return ebcasc[c];
 #else
+  fprintf (stderr, "mvs_map_char: !TE & !HE: c = %02x\n", c);
   return c;
 #endif
 #endif
 }
 
+/* ===================================================== */
+/* 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
    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
 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;
       fprintf (assembler_source, "\tL\t%d,%d(,%d)\n",
          BASE_REGISTER, (mvs_page_num - function_base_page) * 4,
@@ -264,12 +568,19 @@ check_label_emit (void)
    allocated from memory.
    ID is the label number of the label being added to the list.  */
 
-int
-mvs_add_label (id)
+label_node_t *
+mvs_get_label (id)
      int id;
 {
   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)
     {
       lp = free_anchor;
@@ -277,21 +588,70 @@ mvs_add_label (id)
     }
   else
     {
-      lp = (label_node_t *) malloc (sizeof (label_node_t));
-      if (lp == 0)
-       {
-         fatal ("virtual memory exhausted\n");
-         abort ();
-       }
+      lp = (label_node_t *) xmalloc (sizeof (label_node_t));
     }
+
+  /* initialize for new label */
   lp->label_id = id;
-  lp->label_page = mvs_page_num;
+  lp->label_page = -1;
   lp->label_next = label_anchor;
+  lp->label_first_ref = 2000123123;
+  lp->label_last_ref = -1;
+  lp->label_addr = -1;
+  lp->first_ref_page = -1;
   label_anchor = lp;
+
+  return lp;
 }
 
-/* Check to see if the label is in the list.  If 1 is returned then a load
-   and branch on register must be generated.
+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 and in the current
+   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.  */
 
 int
@@ -302,27 +662,55 @@ mvs_check_label (id)
 
   for (lp = label_anchor; lp; lp = lp->label_next)
     {
-      if (lp->label_id == id)
-       return 1;
+      if (lp->label_id == id) 
+        {
+          if (lp->label_page == mvs_page_num) 
+            {
+               return 1;
+            } 
+          else 
+            {
+              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
    label element chain.  */
 
-int
-mvs_free_label (void)
+void
+mvs_free_label_list (void)
 {
+
   if (label_anchor)
     {
-      if (free_anchor)
-       label_anchor->label_next = free_anchor;
+      label_node_t *last_lp = label_anchor;
+      while (last_lp->label_next) last_lp = last_lp->label_next;
+      last_lp->label_next = free_anchor;
       free_anchor = label_anchor;
     }
   label_anchor = 0;
 }
 
+/* ====================================================================== */
 /* If the page size limit is reached a new code page is started, and the base
    register is set to it.  This page break point is counted conservatively,
    most literals that have the same value are collapsed by the assembler.
@@ -331,6 +719,7 @@ mvs_free_label (void)
    CODE is the length, in bytes, of the instruction to be emitted.
    LIT is the length of the literal to be emitted.  */
 
+#ifdef TARGET_HLASM
 int
 mvs_check_page (file, code, lit)
      FILE *file;
@@ -348,10 +737,11 @@ mvs_check_page (file, code, lit)
       fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num);
       fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER);
       mvs_page_num++;
-      fprintf (assembler_source, "\tBALR\t%d,0\n", BASE_REGISTER);
+      /* 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, "\tUSING\t*,%d\n", BASE_REGISTER);
-      mvs_free_label ();
       mvs_page_code = code;
       mvs_page_lit = lit;
       return 1;
@@ -360,6 +750,53 @@ mvs_check_page (file, code, lit)
   mvs_page_lit += lit;
   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
    conventions.  True is returned if the function is in the table.
@@ -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.
    OP is the current operation.
    MODE is the current operation mode.  */
@@ -460,31 +1144,57 @@ r_or_s_operand (op, mode)
 }
 
 
-/* Return 1 if the next instruction is an unsigned jump instruction.
-   INSN is the current instruction.  */
+/* Some remarks about unsigned_jump_follows_p():
+   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)
      register rtx insn;
 {
-  insn = NEXT_INSN (insn);
-  if (GET_CODE (insn) != JUMP_INSN)
-    return 0;
-
-  insn = XEXP (insn, 3);
-  if (GET_CODE (insn) != SET)
-    return 0;
+  rtx orig_insn = insn;
+  while (1) 
+    {
+      register rtx tmp_insn;
+      enum rtx_code coda;
+  
+      insn = NEXT_INSN (insn);
+      if (!insn) fatal_insn ("internal error--no jump follows compare:", orig_insn);
+  
+      if (GET_CODE (insn) != JUMP_INSN) continue;
+    
+      tmp_insn = XEXP (insn, 3);
+      if (GET_CODE (tmp_insn) != SET) continue;
+    
+      if (GET_CODE (XEXP (tmp_insn, 0)) != PC) continue;
+    
+      tmp_insn = XEXP (tmp_insn, 1);
+      if (GET_CODE (tmp_insn) != IF_THEN_ELSE) continue;
+    
+      /* 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;
+    }
+}
 
-  if (GET_CODE (XEXP (insn, 0)) != PC)
-    return 0;
 
-  insn = XEXP (insn, 1);
-  if (GET_CODE (insn) != IF_THEN_ELSE)
-    return 0;
-
-  insn = XEXP (insn, 0);
-  return GET_CODE (insn) != GE && GET_CODE (insn) != GT
-    && GET_CODE (insn) != LE && GET_CODE (insn) != LT;
-}
+#ifdef TARGET_HLASM
 
 void
 i370_function_prolog (f, l)
@@ -492,22 +1202,85 @@ i370_function_prolog (f, l)
      int l;
 {
 #if MACROPROLOGUE == 1
+  fprintf (f, "* Function %s prologue\n", mvs_function_name);
   fprintf (f, "\tEDCPRLG USRDSAL=%d,BASEREG=%d\n",
           STACK_POINTER_OFFSET + l - 120 +
           current_function_outgoing_args_size, BASE_REGISTER);
-  fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
-  fprintf (f, "\tLR\t11,1\n");
-  fprintf (f, "\tL\t%d,=A(PGT%d)\n", PAGE_REGISTER, mvs_page_num);
-  mvs_page_code = 6;
-  mvs_page_lit = 4;
-  mvs_check_page (f, 0, 0);
-  function_base_page = mvs_page_num;
 #else /* MACROPROLOGUE != 1 */
   static int function_label_index = 1;
   static int function_first = 0;
   static int function_year, function_month, function_day;
   static int function_hour, function_minute, function_second;
   int i;
+#if 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)
     {
       struct tm *function_time;
@@ -530,26 +1303,27 @@ i370_function_prolog (f, l)
                 function_hour, function_minute, function_second);
       fprintf (f, "\tDC\tCL2'01',CL4'0100'\n");
     }
-  fprintf (f, "$DSD%03d\tDSECT\n", function_label_index);
+  fprintf (f, "* Function %s prologue\n", mvs_function_name);
+  fprintf (f, "FDSD%03d\tDSECT\n", function_label_index);
   fprintf (f, "\tDS\tD\n");
   fprintf (f, "\tDS\tCL(%d)\n", STACK_POINTER_OFFSET + l
                        + current_function_outgoing_args_size);
-  fprintf (f, "\tORG\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, "\tORG\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);
   fprintf (f, "\tDS\t0H\n");
   assemble_name (f, mvs_function_name);
-  fprintf (f, "\tEQU\t*\n");
+  fprintf (f, "\tCSECT\n");
   fprintf (f, "\tUSING\t*,15\n");
   fprintf (f, "\tB\tFPL%03d\n", function_label_index);
   fprintf (f, "\tDC\tAL1(FPL%03d+4-*)\n", function_label_index + 1);
   fprintf (f, "\tDC\tX'CE',X'A0',AL1(16)\n");
   fprintf (f, "\tDC\tAL4(PPA2)\n");
   fprintf (f, "\tDC\tAL4(0)\n");
-  fprintf (f, "\tDC\tAL4($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, "\tDC\tAL2(%d),C'%s'\n", strlen (mvs_function_name),
        mvs_function_name);
@@ -570,15 +1344,149 @@ i370_function_prolog (f, l)
   fprintf (f, "\tLR\t13,2\n");
   fprintf (f, "\tDROP\t15\n");
   fprintf (f, "\tBALR\t%d,0\n", BASE_REGISTER);
-  fprintf (f, "PG%d\tEQU\t*\n", mvs_page_num );
   fprintf (f, "\tUSING\t*,%d\n", BASE_REGISTER);
-  fprintf (f, "\tLR\t11,1\n");
+  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, "\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_check_page (f, 0, 0);
   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_label_index += 2;
-#endif /* MACROPROLOGUE */
+  function_label_index ++;
+
+  fprintf (f, ".LPG%d:\n", mvs_page_num  );
+  fprintf (f, "\tL\tr%d,=A(.LPGT%d)\n", PAGE_REGISTER, mvs_page_num);
+  fprintf (f, "# Function code\n");
+
+  mvs_free_label_list ();
+  mvs_page_code = 6;
+  mvs_page_lit = 4;
+  mvs_check_page (f, 0, 0);
+  function_base_page = mvs_page_num;
+
+  /* find all labels in this routine */
+  i370_label_scan ();
 }
+#endif /* TARGET_ELF_ABI */
index 3c54acfd56e5f00f0e83d3de8aa438d5359eb244..c37249a346c66d143ae7512a971dc86e2c973875 100644 (file)
@@ -1,7 +1,8 @@
 /* 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 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.
 
@@ -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,
 Boston, MA 02111-1307, USA.  */
 
-#define TARGET_VERSION printf (" (370/MVS)");
-
-/* 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)"
-
+#ifndef __I370_H__
+#define __I370_H__
 /* Run-time compilation parameters selecting different hardware subsets.  */
 
 extern int target_flags;
@@ -42,10 +35,6 @@ extern int mvs_page_code, mvs_page_lit;
 
 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.  */
 
 extern char *mvs_function_name;
@@ -74,9 +63,9 @@ extern int current_function_outgoing_args_size;
    An empty string NAME is used to identify the default VALUE.  */
 
 #define TARGET_SWITCHES                                                        \
-{ { "char-instructions", 1, "Generate char instructions"},             \
-  { "no-char-instructions", -1, "Do not generate char instructions"},  \
-  { "", TARGET_DEFAULT, NULL} }
+{ { "char-instructions", 1, "Generate char instructions"},            \
+  { "no-char-instructions", -1, "Do not generate char instructions"}, \
+  { "", TARGET_DEFAULT} }
 
 /* To use IBM supplied macro function prologue and epilogue, define the
    following to 1.  Should only be needed if IBM changes the definition
@@ -150,20 +139,37 @@ extern int current_function_outgoing_args_size;
 #define TARGET_FLOAT_FORMAT IBM_FLOAT_FORMAT
 
 /* 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
 #define MAP_CHARACTER(c) ((char)(c))
 #else
 #define MAP_CHARACTER(c) ((char)mvs_map_char (c))
 #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 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                                                        \
 { 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;
 #define PAGE_REGISTER 4
 
 /* 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)
-   pointer, R12 is the TCA pointer, R3 is the base register, R4 is the page
-   origin table pointer and R11 is the arg pointer.  */
+   for the register allocator.  These are registers that must have fixed,
+   valid values stored in them for the entire length of the subroutine call,
+   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                                                \
 { 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;
    saved.
    The latter must include the registers where values are returned
    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                                            \
 { 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;
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something 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)                                  \
-  ((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.
    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
-   either SF or DF.  */
+   either SF, DF, SC or DC.  */
 
 #define HARD_REGNO_MODE_OK(REGNO, MODE)                                        \
-  ((REGNO) < 16 ? ((REGNO) & 1) == 0 || (MODE) != DImode               \
-               : (MODE) == SFmode || (MODE) == DFmode)
+  ((REGNO) < 16 ? (((REGNO) & 1) == 0 ||                               \
+                 (((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
    mode MODE1 and one has mode MODE2.
@@ -263,12 +311,29 @@ extern int current_function_outgoing_args_size;
 
 #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
 
-/* Register in which address to store a structure value is passed to
-   a function.  */
+/* R1 is register in which address to store a structure value is passed to
+   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
 
@@ -347,23 +412,36 @@ enum reg_class
 
 #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,
    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
-   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)                               \
     (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) == SYMBOL_REF ||                                      \
      GET_CODE(X) == CONST ? ADDR_REGS : (CLASS))
 
 /* 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)                                   \
-  ((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)
 
 /* Stack layout; function entry, exit and calling.  */
@@ -455,17 +533,26 @@ enum reg_class
 
 #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
 
-/* Define how to find the value returned by a function.  VALTYPE is the
-   data type of the value (as a tree).
+/* The FUNCTION_VALUE macro dDefines how to find the value returned by a 
+   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;
-   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)                                          \
-  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
    the value has mode MODE.  */
@@ -481,84 +568,6 @@ enum reg_class
 
 #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
    trampoline, leaving space for the variable parts.
@@ -572,15 +581,21 @@ enum reg_class
         BR    15
    X    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)                                      \
 {                                                                      \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0x05E0));                           \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0x5800 | STATIC_CHAIN_REGNUM << 4));        \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0xE00A));                           \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0x58F0));                           \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0xE00E));                           \
-  ASM_OUTPUT_SHORT (FILE, GEN_INT (0x07FF));                           \
+  ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x05E0));      \
+  ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x5800 |       \
+                          STATIC_CHAIN_REGNUM << 4));                  \
+  ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0xE00A));      \
+  ASM_OUTPUT_SHORT (FILE, gen_rtx (CONST_INT, VOIDmode, 0x58F0));      \
+  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);                                 \
@@ -599,12 +614,6 @@ enum reg_class
   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
    pointer does not matter (provided there is a frame pointer).  */
 
@@ -612,11 +621,11 @@ enum reg_class
 
 /* Addressing modes, and classification of registers for them.  */
 
-/* #define HAVE_POST_INCREMENT */
-/* #define HAVE_POST_DECREMENT */
+/* #define HAVE_POST_INCREMENT */
+/* #define HAVE_POST_DECREMENT */
 
-/* #define HAVE_PRE_DECREMENT */
-/* #define HAVE_PRE_INCREMENT */
+/* #define HAVE_PRE_DECREMENT */
+/* #define HAVE_PRE_INCREMENT */
 
 /* 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
@@ -712,11 +721,14 @@ enum reg_class
    that wants to use this 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)                                      \
- if (REG_P (X) && REG_OK_FOR_BASE_P (X))                               \
-   REGS += 1;                                                          \
+ if (REG_P (X)) {                                                      \
+   if (REG_OK_FOR_BASE_P (X)) REGS += 1;                               \
+   else goto FAIL;                                                     \
+ }                                                                     \
  else if (GET_CODE (X) != CONST_INT || (unsigned) INTVAL (X) >= 4096)  \
    goto FAIL;
 
@@ -760,9 +772,26 @@ enum reg_class
 
 #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.
-   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)                         \
 {                                                                      \
@@ -787,11 +816,11 @@ enum reg_class
 
 #define CASE_VECTOR_MODE SImode
 
-/* Define as C expression which evaluates to nonzero if the tablejump
-   instruction expects the table to contain offsets from the address of the
-   table.
-   Do not define this if the table should contain absolute addresses. */
-/* #define CASE_VECTOR_PC_RELATIVE */
+/* Define this if the tablejump instruction expects the table to contain
+   offsets from the address of the table.
+   Do not define this if the table should contain absolute addresses.  */
+
+/* #define CASE_VECTOR_PC_RELATIVE */
 
 /* Specify the tree operation to be used to convert reals to integers.  */
 
@@ -816,7 +845,7 @@ enum reg_class
 
 /* 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.  */
 
@@ -871,6 +900,18 @@ enum reg_class
   case CONST_DOUBLE:                                                   \
     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.  */
 
 /* Here we define machine-dependent flags and fields in cc_status
@@ -883,7 +924,18 @@ enum reg_class
    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
    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)                                    \
 {                                                                      \
@@ -910,11 +962,17 @@ enum reg_class
            cc_status.value2 = 0;                                       \
          switch (GET_CODE (XEXP (exp, 1)))                             \
            {                                                           \
-             case PLUS:     case MINUS: case MULT:   /* case UMULT: */ \
-             case DIV:      case UDIV:  case NEG:    case ASHIFT:      \
-             case ASHIFTRT: case AND:   case IOR:    case XOR:         \
-             case ABS:      case NOT:                                  \
+             case PLUS:     case MINUS: case NEG:                      \
+             case NOT:  case ABS:                                      \
                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
 #define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV)                              \
 { if (cc_status.flags & CC_NO_OVERFLOW)        return NO_OV; return NORMAL; }
 
+/* ------------------------------------------ */
 /* 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 DATA_SECTION_ASM_OP "* Program data 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_END          /* NO OP */
+#define MAX_MVS_LABEL_SIZE 8
 
 /* How to refer to registers in assembler output.  This sequence is
    indexed by compiler's hard-register-number (see above).  */
@@ -952,10 +1043,12 @@ enum reg_class
 }
 
 /* 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 ("\tRMODE\tANY\n", FILE);                                      \
+  fputs ("\tCSECT\n", FILE); }
 
-#define ASM_FILE_START(FILE) fputs ("\tCSECT\n", FILE);
 #define ASM_FILE_END(FILE) fputs ("\tEND\n", FILE);
 #define ASM_IDENTIFY_GCC(FILE)
 #define ASM_COMMENT_START "*"
@@ -965,26 +1058,36 @@ enum reg_class
 #define ASM_OUTPUT_LABEL(FILE, NAME)                                   \
 { 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)                                        \
-{ 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.
    The '_' is mapped to '@', except for MVS functions, then '#'.  */
 
-#define MAX_MVS_LABEL_SIZE 8
 
 #define ASM_OUTPUT_LABELREF(FILE, NAME)                                        \
 {                                                                      \
   char *bp, ch, temp[MAX_MVS_LABEL_SIZE + 1];                          \
-  if (strlen (NAME) > MAX_MVS_LABEL_SIZE)                              \
-    {                                                                  \
-      strncpy (temp, NAME, MAX_MVS_LABEL_SIZE);                                \
-      temp[MAX_MVS_LABEL_SIZE] = '\0';                                 \
-    }                                                                  \
-  else                                                                 \
-    strcpy (temp,NAME);                                                        \
+  if (!mvs_get_alias (NAME, temp))                                     \
+    strcpy (temp, NAME);                                               \
   if (!strcmp (temp,"main"))                                           \
     strcpy (temp,"gccmain");                                           \
   if (mvs_function_check (temp))                                       \
@@ -994,7 +1097,7 @@ enum reg_class
   for (bp = temp; *bp; bp++)                                           \
     {                                                                  \
       if (islower (*bp)) *bp = toupper (*bp);                          \
-      if (*bp == '_') *bp = ch;                                                \
+      else if (*bp == '_') *bp = ch;                                   \
     }                                                                  \
   fprintf (FILE, "%s", temp);                                          \
 }
@@ -1010,12 +1113,13 @@ enum reg_class
   if (!strcmp (PREFIX,"L"))                                            \
     {                                                                  \
       mvs_add_label(NUM);                                              \
-      mvs_label_emitted = 1;                                           \
     }                                                                  \
   fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM);                       \
 }
 
 /* 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)                        \
    fprintf (FILE, "%s%d\tEQU\t*\n", PREFIX, NUM)
@@ -1033,11 +1137,15 @@ enum reg_class
   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.
-   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)                               \
   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)
 
 /* This is how to output an insn to pop a register from the stack.
@@ -1045,16 +1153,18 @@ enum reg_class
 
 #define ASM_OUTPUT_REG_POP(FILE, REGNO)                                        \
   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)
 
+/* 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.  */
-
 #define ASM_OUTPUT_DOUBLE(FILE, VALUE)                                 \
   fprintf (FILE, "\tDC\tD'%.18G'\n", (VALUE))
 
 /* This is how to output an assembler line defining a `float' constant.  */
-
 #define ASM_OUTPUT_FLOAT(FILE, VALUE)                                  \
   fprintf (FILE, "\tDC\tE'%.9G'\n", (VALUE))
 
@@ -1169,6 +1279,11 @@ enum reg_class
 
 #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);                                           \
   assemble_name (FILE, NAME);                                          \
   fputs ("\n", FILE);                                                  \
@@ -1199,41 +1314,25 @@ enum reg_class
   sprintf ((OUTPUT), "%s%d", (NAME), (LABELNO));                       \
 }
 
-/* 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.  */
-
-#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.
+/* 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 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];                                           \
       case REG:                                                                \
        if (CODE == 'N')                                                \
-           strcpy (curreg, reg_names[REGNO (X) + 1]);                  \
+           strcpy (curreg, reg_names[REGNO (XV) + 1]);                 \
        else                                                            \
-           strcpy (curreg, reg_names[REGNO (X)]);                      \
+           strcpy (curreg, reg_names[REGNO (XV)]);                     \
        fprintf (FILE, "%s", curreg);                                   \
        break;                                                          \
       case MEM:                                                                \
        {                                                               \
-         rtx addr = XEXP (X, 0);                                       \
+         rtx addr = XEXP (XV, 0);                                      \
          if (CODE == 'O')                                              \
            {                                                           \
              if (GET_CODE (addr) == PLUS)                              \
@@ -1249,61 +1348,81 @@ enum reg_class
                fprintf (FILE, "%s", reg_names[REGNO (addr)]);          \
            }                                                           \
          else                                                          \
-           output_address (XEXP (X, 0));                               \
+           output_address (XEXP (XV, 0));                              \
        }                                                               \
        break;                                                          \
       case SYMBOL_REF:                                                 \
       case LABEL_REF:                                                  \
        mvs_page_lit += 4;                                              \
-       if (SYMBOL_REF_FLAG (X)) fprintf (FILE, "=V(");                 \
-       else                     fprintf (FILE, "=A(");                 \
-       output_addr_const (FILE, X);                                    \
+       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 (X) & 0xff);                      \
+         fprintf (FILE, "%d", INTVAL (XV) & 0xff);                     \
        else if (CODE == 'X')                                           \
-         fprintf (FILE, "%02X", INTVAL (X) & 0xff);                    \
+         fprintf (FILE, "%02X", INTVAL (XV) & 0xff);                   \
        else if (CODE == 'h')                                           \
-         fprintf (FILE, "%d", (INTVAL (X) << 16) >> 16);               \
+         fprintf (FILE, "%d", (INTVAL (XV) << 16) >> 16);              \
        else if (CODE == 'H')                                           \
          {                                                             \
            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                                                            \
          {                                                             \
            mvs_page_lit += 4;                                          \
-           fprintf (FILE, "=F'%d'", INTVAL (X));                       \
+           fprintf (FILE, "=F'%d'", INTVAL (XV));                      \
          }                                                             \
        break;                                                          \
       case CONST_DOUBLE:                                               \
-       if (GET_MODE (X) == DImode)                                     \
+       if (GET_MODE (XV) == DImode)                                    \
          {                                                             \
            if (CODE == 'M')                                            \
              {                                                         \
                mvs_page_lit += 4;                                      \
-               fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_LOW (X));     \
+               fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_LOW (XV));    \
              }                                                         \
            else if (CODE == 'L')                                       \
              {                                                         \
                mvs_page_lit += 4;                                      \
-               fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_HIGH (X));    \
+               fprintf (FILE, "=XL4'%08X'", CONST_DOUBLE_HIGH (XV));   \
              }                                                         \
            else                                                        \
              {                                                         \
                mvs_page_lit += 8;                                      \
-               fprintf (FILE, "=XL8'%08X%08X'", CONST_DOUBLE_LOW (X),  \
-                       CONST_DOUBLE_HIGH (X));                         \
+               fprintf (FILE, "=XL8'%08X%08X'", CONST_DOUBLE_LOW (XV), \
+                       CONST_DOUBLE_HIGH (XV));                        \
              }                                                         \
          }                                                             \
        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;                            \
-           u.i[0] = CONST_DOUBLE_LOW (X);                              \
-           u.i[1] = CONST_DOUBLE_HIGH (X);                             \
-           if (GET_MODE (X) == SFmode)                                 \
+           u.i[0] = CONST_DOUBLE_LOW (XV);                             \
+           u.i[1] = CONST_DOUBLE_HIGH (XV);                            \
+           if (GET_MODE (XV) == SFmode)                                \
              {                                                         \
                mvs_page_lit += 4;                                      \
                fprintf (FILE, "=E'%.9G'", u.d);                        \
@@ -1316,22 +1435,22 @@ enum reg_class
          }                                                             \
        break;                                                          \
       case CONST:                                                      \
-       if (GET_CODE (XEXP (X, 0)) == PLUS                              \
-          && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF)           \
+       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 (X, 0), 0)))                \
+           if (SYMBOL_REF_FLAG (XEXP (XEXP (XV, 0), 0)))               \
              {                                                         \
                fprintf (FILE, "=V(");                                  \
                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,             \
-                                 INTVAL (XEXP (XEXP (X, 0), 1)));      \
+                                 INTVAL (XEXP (XEXP (XV, 0), 1)));     \
              }                                                         \
            else                                                        \
              {                                                         \
                fprintf (FILE, "=A(");                                  \
-               output_addr_const (FILE, X);                            \
+               output_addr_const (FILE, XV);                           \
                fprintf (FILE, ")");                                    \
              }                                                         \
          }                                                             \
@@ -1339,7 +1458,7 @@ enum reg_class
          {                                                             \
            mvs_page_lit += 4;                                          \
            fprintf (FILE, "=F'");                                      \
-           output_addr_const (FILE, X);                                \
+           output_addr_const (FILE, XV);                               \
            fprintf (FILE, "'");                                        \
          }                                                             \
        break;                                                          \
@@ -1438,3 +1557,578 @@ enum reg_class
        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__ */
index 16e2c95dc76eb35c29eb206e04923112d59a0ac2..8896f2a80217cc4957f5ed425aabab85f2a75393 100644 (file)
@@ -1,7 +1,8 @@
 ;;- 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).
-;;  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.
 
@@ -20,9 +21,9 @@
 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
 ;; 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:
 ;;
 ;;    I -- An 8-bit constant (0..255).
 ;;    J -- A 12-bit constant (0..4095).
 ;;    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.
 ;;
 ;;   %B -- Print a constant byte integer.
 ;;   %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.
 ;;   %M -- Print most significant word of a CONST_DOUBLE.
 ;;   %N -- Print next register (second word of a DImode reg).
 ;;   %O -- Print the offset 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.
+;;   %W -- Print a signed 32-bit int sign-extended to 64-bits.
 ;;
 ;; We have a special constraint for pattern matching.
 ;;
 ;; Some *di patterns have been commented out per advice from RMS, as gcc
 ;; 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.
   check_label_emit ();
   mvs_check_page (0, 4, 0);
   return \"SRDA        %0,0\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; tstsi instruction pattern(s).
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LTR %0,%0\";
-}")
+}"
+   [(set_attr "length" "2")]
+)
 
 ;
 ; tsthi instruction pattern(s).
   check_label_emit ();
   mvs_check_page (0, 4, 2);
   return \"CH  %0,=H'0'\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; tstqi instruction pattern(s).
   check_label_emit ();
   if (REG_P (operands[0]))
     {
+      /* an unsigned compare to zero is always zero/not-zero... */
       mvs_check_page (0, 4, 4);
       return \"N       %0,=X'000000FF'\";
     }
   mvs_check_page (0, 4, 0);
   return \"CLI %0,0\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 (define_insn "tstqi"
   [(set (cc0)
   check_label_emit ();
   if (unsigned_jump_follows_p (insn))
     {
+      /* an unsigned compare to zero is always zero/not-zero... */
       mvs_check_page (0, 4, 4);
       return \"N       %0,=X'000000FF'\";
     }
   mvs_check_page (0, 8, 0);
   return \"SLL %0,24\;SRA      %0,24\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; tstdf instruction pattern(s).
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LTDR        %0,%0\";
-}")
+}"
+   [(set_attr "length" "2")]
+)
 
 ;
 ; tstsf instruction pattern(s).
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LTER        %0,%0\";
-}")
+}"
+   [(set_attr "length" "2")]
+)
 
 ;;
 ;;- Compare instructions.
   if (unsigned_jump_follows_p (insn))
     return \"CL        %0,%1\";
   return \"C   %0,%1\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; cmphi instruction pattern(s).
 ;
 
+; depricate constraint d because it takes multiple instructions
+; and a memeory access ...
 (define_insn "cmphi"
   [(set (cc0)
        (compare (match_operand:HI 0 "register_operand" "d")
-                (match_operand:HI 1 "general_operand" "")))]
+                (match_operand:HI 1 "general_operand" "???dim")))]
   ""
   "*
 {
     }
   mvs_check_page (0, 4, 0);
   return \"CH  %0,%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; cmpqi instruction pattern(s).
 
 (define_insn ""
   [(set (cc0)
-       (compare (match_operand:QI 0 "r_or_s_operand" "g")
-                (match_operand:QI 1 "r_or_s_operand" "g")))]
+       (compare (match_operand:QI 0 "r_or_s_operand" "dS")
+                (match_operand:QI 1 "r_or_s_operand" "diS")))]
   "unsigned_jump_follows_p (insn)"
   "*
 {
       if (GET_CODE (operands[1]) == CONST_INT)
        {
          mvs_check_page (0, 4, 1);
-          return \"CLM %0,1,=FL1'%B1'\";
+          return \"CLM %0,1,=X'%X1'\";
         }
       mvs_check_page (0, 4, 0);
       return \"CLM     %0,1,%1\";
       if (REG_P (operands[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);
       return \"CLI     %1,%B0\";
   cc_status.flags |= CC_REVERSED;
   mvs_check_page (0, 4, 0);
   return \"CLM %1,1,%0\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 (define_insn "cmpqi"
   [(set (cc0)
   check_label_emit ();
   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)
        {
          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);
       return \"STC     %1,140(,13)\;CLM        %0,1,140(13)\";
     }
   mvs_check_page (0, 12, 0);
   return \"SLL %0,24\;SRA      %0,24\;C        %0,%1\";
-}")
+}"
+   [(set_attr "length" "18")]
+)
 
 ;
 ; cmpdf instruction pattern(s).
   cc_status.flags |= CC_REVERSED;
   mvs_check_page (0, 4, 0);
   return \"CD  %1,%0\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; cmpsf instruction pattern(s).
@@ -410,7 +468,9 @@ check_label_emit ();
   cc_status.flags |= CC_REVERSED;
   mvs_check_page (0, 4, 0);
   return \"CE  %1,%0\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; cmpstrsi instruction pattern(s).
@@ -437,7 +497,7 @@ check_label_emit ();
     }
   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);
@@ -450,32 +510,41 @@ check_label_emit ();
     }
   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)
     {
-      emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
-               gen_rtx (SET, VOIDmode, operands[0], 
-                       gen_rtx (COMPARE, VOIDmode, op1, op2)),
-               gen_rtx (USE, VOIDmode, operands[3]))));
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+               gen_rtx_SET (VOIDmode, operands[0], 
+                       gen_rtx_COMPARE (VOIDmode, op1, op2)),
+               gen_rtx_USE (VOIDmode, operands[3]))));
     }
   else
     {
-      rtx reg1 = gen_reg_rtx (DImode);
-      rtx reg2 = gen_reg_rtx (DImode);
-      rtx subreg = gen_rtx (SUBREG, SImode, reg1, 1);
-
-      emit_insn (gen_rtx (SET, VOIDmode, subreg, operands[3]));
-      emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, reg2, 1),
-                                           subreg));
-      emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5,
-               gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (COMPARE, VOIDmode, op1, op2)),
-               gen_rtx (USE, VOIDmode, reg1),
-               gen_rtx (USE, VOIDmode, reg2),
-               gen_rtx (CLOBBER, VOIDmode, reg1),
-               gen_rtx (CLOBBER, VOIDmode, reg2))));
+        /* implementation suggested by  Richard Henderson <rth@cygnus.com> */
+        rtx reg1 = gen_reg_rtx (DImode);
+        rtx reg2 = gen_reg_rtx (DImode);
+        rtx result = operands[0];
+        rtx mem1 = operands[1];
+        rtx mem2 = operands[2];
+        rtx len = operands[3];
+        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),
+                        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;
 }")
@@ -492,26 +561,31 @@ check_label_emit ();
 {
   check_label_emit ();
   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.
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "d")
-       (compare (match_operand:BLK 1 "general_operand" "m")
-                (match_operand:BLK 2 "general_operand" "m")))
-   (use (match_operand:DI 3 "register_operand" "d"))
-   (use (match_operand:DI 4 "register_operand" "d"))
-   (clobber (match_dup 3))
-   (clobber (match_dup 4))]
+(define_insn "cmpstrsi_1"
+  [(set (match_operand:SI 0 "register_operand" "+d")
+        (compare
+        (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0))
+        (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "+d") 0))))
+   (use (match_dup 1))
+   (use (match_dup 2))
+   (clobber (match_dup 1))
+   (clobber (match_dup 2))]
   ""
   "*
 {
   check_label_emit ();
-  mvs_check_page (0, 26, 0);
-  return \"LA  %3,%1\;LA       %4,%2\;LA       %0,1\;CLCL      %3,%4\;BH       *+12\;BL        *+6\;SLR        %0,%0\;LNR      %0,%0\";
-}")
+  mvs_check_page (0, 18, 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.
@@ -522,8 +596,11 @@ check_label_emit ();
 ;
 
 (define_insn ""
-  [(set (match_operand:DI 0 "r_or_s_operand" "=dm")
-        (match_operand:DI 1 "r_or_s_operand" "dim*fF"))]
+;;  [(set (match_operand:DI 0 "r_or_s_operand" "=dm")
+;;        (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"
   "*
 {
@@ -551,7 +628,7 @@ check_label_emit ();
        {
          CC_STATUS_INIT;
          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)
        {
@@ -573,12 +650,16 @@ check_label_emit ();
       return \"STM     %1,%N1,%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"
-  [(set (match_operand:DI 0 "general_operand" "=dm")
-       (match_operand:DI 1 "general_operand" "dim*fF"))]
+;;  [(set (match_operand:DI 0 "general_operand" "=d,dm")
+;;     (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 ();
        {
          CC_STATUS_INIT;
          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)
        {
@@ -622,17 +703,64 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"STD     %1,%0\";
     }
-  mvs_check_page (0, 4, 0);
-  return \"STM %1,%N1,%0\";
-}")
+  else if (REG_P (operands[1]))
+    {
+      /* 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).
 ;
 
 (define_insn ""
-  [(set (match_operand:SI 0 "r_or_s_operand" "=dm,dm")
-        (match_operand:SI 1 "r_or_s_operand" "dim,*fF"))]
+;;  [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm")
+;;        (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"
   "*
 {
@@ -659,7 +787,7 @@ check_label_emit ();
          && (unsigned) INTVAL (operands[1]) < 4096)
        {
          mvs_check_page (0, 4, 0);
-         return \"LA   %0,%c1\";
+         return \"LA   %0,%c1(0,0)\";
        }
       mvs_check_page (0, 4, 0);
       return \"L       %0,%1\";
@@ -676,7 +804,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"MVC %O0(4,%R0),%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 (define_insn "movsi"
   [(set (match_operand:SI 0 "general_operand" "=d,dm")
@@ -707,7 +837,7 @@ check_label_emit ();
          && (unsigned) INTVAL (operands[1]) < 4096)
        {
          mvs_check_page (0, 4, 0);
-         return \"LA   %0,%c1\";
+         return \"LA   %0,%c1(0,0)\";
        }
       mvs_check_page (0, 4, 0);
       return \"L       %0,%1\";
@@ -719,7 +849,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"ST  %1,%0\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;(define_expand "movsi"
 ;  [(set (match_operand:SI 0 "general_operand" "=d,dm")
@@ -734,7 +866,7 @@ check_label_emit ();
 ;      && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SYMBOL_REF
 ;      && 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];
@@ -742,10 +874,10 @@ check_label_emit ();
 ;      && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF
 ;      && 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;
 ;}")
 
@@ -777,7 +909,7 @@ check_label_emit ();
          && (unsigned) INTVAL (operands[1]) < 4096)
        {
          mvs_check_page (0, 4, 0);
-         return \"LA   %0,%c1\";
+         return \"LA   %0,%c1(0,0)\";
        }
       if (GET_CODE (operands[1]) == CONST_INT)
        {
@@ -799,7 +931,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"MVC %O0(2,%R0),%1\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "movhi"
   [(set (match_operand:HI 0 "general_operand" "=d,m")
@@ -825,7 +959,7 @@ check_label_emit ();
          && (unsigned) INTVAL (operands[1]) < 4096)
        {
          mvs_check_page (0, 4, 0);
-         return \"LA   %0,%c1\";
+         return \"LA   %0,%c1(0,0)\";
        }
       if (GET_CODE (operands[1]) == CONST_INT)
        {
@@ -837,7 +971,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"STH %1,%0\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; movqi instruction pattern(s).
@@ -865,10 +1001,11 @@ check_label_emit ();
        }
       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);
-             return \"LA       %0,%c1\";
+             return \"LA       %0,%c1(0,0)\";
            }
          mvs_check_page (0, 4, 0);
          return \"L    %0,=F'%c1'\";
@@ -888,7 +1025,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"MVC %O0(1,%R0),%1\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "movqi"
   [(set (match_operand:QI 0 "general_operand" "=d,m")
@@ -912,10 +1051,11 @@ check_label_emit ();
        }
       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);
-             return \"LA       %0,%c1\";
+             return \"LA       %0,%c1(0,0)\";
            }
          mvs_check_page (0, 4, 0);
          return \"L    %0,=F'%c1'\";
@@ -925,13 +1065,15 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 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"))
        (match_operand:QI 1 "general_operand" "g"))]
   ""
@@ -945,7 +1087,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"IC  %0,%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; movstricthi instruction pattern(s).
@@ -970,9 +1114,11 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   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"))
        (match_operand:HI 1 "general_operand" "d"))]
   ""
@@ -986,15 +1132,20 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"STH %1,%0\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; movdf instruction pattern(s).
 ;
 
 (define_insn ""
-  [(set (match_operand:DF 0 "r_or_s_operand" "=fm,fm,*dm")
-        (match_operand:DF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
+;;  [(set (match_operand:DF 0 "r_or_s_operand" "=fm,fm,*dm")
+;;        (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"
   "*
 {
@@ -1027,6 +1178,11 @@ check_label_emit ();
          mvs_check_page (0, 12, 0);
          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);
       return \"LM      %0,%N0,%1\";
     }
@@ -1041,12 +1197,17 @@ check_label_emit ();
       return \"STM     %1,%N1,%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"
-  [(set (match_operand:DF 0 "general_operand" "=f,fm,m,*d")
-       (match_operand:DF 1 "general_operand" "fmF,*d,f,fmF"))]
+;;  [(set (match_operand:DF 0 "general_operand" "=f,fm,m,*d")
+;;     (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 ();
          mvs_check_page (0, 12, 0);
          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);
       return \"LM      %0,%N0,%1\";
     }
@@ -1089,15 +1255,22 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"STM %1,%N1,%0\";
-}")
+}"
+   [(set_attr "length" "12")]
+)
 
 ;
 ; movsf instruction pattern(s).
 ;
 
 (define_insn ""
-  [(set (match_operand:SF 0 "r_or_s_operand" "=fm,fm,*dm")
-        (match_operand:SF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
+;;  [(set (match_operand:SF 0 "r_or_s_operand" "=fm,fm,*dm")
+;;        (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"
   "*
 {
@@ -1130,6 +1303,11 @@ check_label_emit ();
          mvs_check_page (0, 8, 0);
          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);
       return \"L       %0,%1\";
     }
@@ -1145,7 +1323,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"MVC %O0(4,%R0),%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 (define_insn "movsf"
   [(set (match_operand:SF 0 "general_operand" "=f,fm,m,*d")
@@ -1192,16 +1372,72 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 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).
-;
+; block must be less than 16M (24 bits) in length
 
 (define_expand "movstrsi"
   [(set (match_operand:BLK 0 "general_operand" "")
         (match_operand:BLK 1 "general_operand" ""))
-   (use (match_operand:SI 2 "general_operand" ""))
+   (use (match_operand:SI  2 "general_operand" ""))
    (match_operand 3 "" "")]
    ""
    "
@@ -1229,27 +1465,35 @@ check_label_emit ();
                          copy_to_mode_reg (SImode, op1));
 
   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_rtx (SET, VOIDmode, op0, op1),
-                                  gen_rtx (USE, VOIDmode, operands[2]))));
+                                  gen_rtx_SET (VOIDmode, op0, op1),
+                                  gen_rtx_USE (VOIDmode, operands[2]))));
 
   else
     {
-      rtx reg1 = gen_reg_rtx (DImode);
-      rtx reg2 = gen_reg_rtx (DImode);
-      rtx subreg = gen_rtx (SUBREG, SImode, reg1, 1);
-
-      emit_insn (gen_rtx (SET, VOIDmode, subreg, operands[2]));
-      emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, reg2, 1),
-                         subreg));
-      emit_insn (gen_rtx (PARALLEL, VOIDmode,
-                         gen_rtvec (5,
-                                    gen_rtx (SET, VOIDmode, op0, op1),
-                                    gen_rtx (USE, VOIDmode, reg1),
-                                    gen_rtx (USE, VOIDmode, reg2),
-                                    gen_rtx (CLOBBER, VOIDmode, reg1),
-                                    gen_rtx (CLOBBER, VOIDmode, reg2))));
+        /* implementation provided by  Richard Henderson <rth@cygnus.com> */
+        rtx reg1 = gen_reg_rtx (DImode);
+        rtx reg2 = gen_reg_rtx (DImode);
+        rtx mem1 = operands[0];
+        rtx mem2 = operands[1];
+        rtx len = operands[2];
+        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),
+                        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;
 }")
@@ -1266,24 +1510,28 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 6, 0);
   return \"MVC %O0(%c2,%R0),%1\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 ; Move a block that is larger than 255 bytes in length.
 
-(define_insn ""
-  [(set (match_operand:BLK 0 "general_operand" "=m")
-        (match_operand:BLK 1 "general_operand" "m"))
-   (use (match_operand:DI 2 "register_operand" "d"))
-   (use (match_operand:DI 3 "register_operand" "d"))
-   (clobber (match_dup 2))
-   (clobber (match_dup 3))]
+(define_insn "movstrsi_1"
+  [(set (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "+d") 0))
+        (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0)))
+   (use (match_dup 0))
+   (use (match_dup 1))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))]
   ""
   "*
 {
   check_label_emit ();
-  mvs_check_page (0, 10, 0);
-  return \"LA  %2,%0\;LA       %3,%1\;MVCL     %2,%3\";
-}")
+  mvs_check_page (0, 2, 0);
+  return \"MVCL        %0,%1\";
+}"
+   [(set_attr "length" "2")]
+)
 
 ;;
 ;;- Conversion instructions.
@@ -1294,34 +1542,34 @@ check_label_emit ();
 ;
 
 (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" "")))]
   ""
   "
 {
   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]));
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (ASHIFTRT, DImode, operands[0],
-                               GEN_INT (32))));
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_ASHIFTRT (DImode, operands[0],
+                               gen_rtx_CONST_INT (SImode, 32))));
     }
   else
     {
       if (INTVAL (operands[1]) < 0)
        {
-         emit_insn (gen_rtx (SET, VOIDmode,
+         emit_insn (gen_rtx_SET (VOIDmode,
                                  operand_subword (operands[0], 0, 1, DImode),
-                              GEN_INT (-1)));
+                              gen_rtx_CONST_INT (SImode, -1)));
         }
       else
        {
-         emit_insn (gen_rtx (SET, VOIDmode,
+         emit_insn (gen_rtx_SET (VOIDmode,
                                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]));
     }
   DONE;
@@ -1343,7 +1591,7 @@ check_label_emit ();
       if (REG_P (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\";
          }
         else
@@ -1358,7 +1606,7 @@ check_label_emit ();
          && (unsigned) INTVAL (operands[1]) < 4096)
        {
          mvs_check_page (0, 4, 0);
-         return \"LA   %0,%c1\";
+         return \"LA   %0,%c1(0,0)\";
        }
       if (GET_CODE (operands[1]) == CONST_INT)
        {
@@ -1368,9 +1616,11 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       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\";
-}")
+}"
+   [(set_attr "length" "12")]
+)
 
 ;
 ; extendqisi2 instruction pattern(s).
@@ -1396,7 +1646,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 12, 0);
   return \"IC  %0,%1\;SLL      %0,24\;SRA      %0,24\";
-}")
+}"
+   [(set_attr "length" "12")]
+)
 
 ;
 ; extendqihi2 instruction pattern(s).
@@ -1422,23 +1674,25 @@ check_label_emit ();
     }
   mvs_check_page (0, 12, 0);
   return \"IC  %0,%1\;SLL      %0,24\;SRA      %0,24\";
-}")
+}"
+   [(set_attr "length" "12")]
+)
 
 ;
 ; zero_extendsidi2 instruction pattern(s).
 ;
 
 (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" "")))]
   ""
   "
 {
-      emit_insn (gen_rtx (SET, VOIDmode,
+      emit_insn (gen_rtx_SET (VOIDmode,
                  operand_subword (operands[0], 0, 1, DImode), operands[1]));
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (LSHIFTRT, DImode, operands[0],
-                               GEN_INT (32))));
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_LSHIFTRT (DImode, operands[0],
+                               gen_rtx_CONST_INT (SImode, 32))));
   DONE;
 }")
 
@@ -1453,10 +1707,13 @@ 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);
   return \"N   %1,=X'0000FFFF'\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; zero_extendqisi2 instruction pattern(s).
@@ -1471,19 +1728,22 @@ check_label_emit ();
   check_label_emit ();
   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);
       return \"N       %0,=X'000000FF'\";
     }
   if (GET_CODE (operands[1]) == CONST_INT)
     {
       mvs_check_page (0, 4, 0);
-      return \"LA      %0,%c1\";
+      return \"LA      %0,%c1(0,0)\";
     }
   CC_STATUS_INIT;
   mvs_check_page (0, 8, 0);
   return \"SLR %0,%0\;IC       %0,%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; zero_extendqihi2 instruction pattern(s).
@@ -1498,19 +1758,22 @@ check_label_emit ();
   check_label_emit ();
   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);
       return \"N       %0,=X'000000FF'\";
     }
   if (GET_CODE (operands[1]) == CONST_INT)
     {
       mvs_check_page (0, 4, 0);
-      return \"LA      %0,%c1\";
+      return \"LA      %0,%c1(0,0)\";
     }
   CC_STATUS_INIT;
   mvs_check_page (0, 8, 0);
   return \"SLR %0,%0\;IC       %0,%1\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; truncsihi2 instruction pattern(s).
@@ -1531,7 +1794,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"STH %1,%0\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; fix_truncdfsi2 instruction pattern(s).
@@ -1539,7 +1804,7 @@ check_label_emit ();
 
 (define_insn "fix_truncdfsi2"
   [(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))]
   ""
   "*
@@ -1553,7 +1818,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 14, 8);
   return \"LDR 0,%1\;AD        0,=XL8'4F08000000000000'\;STD   0,140(,13)\;L   %0,144(,13)\";
-}")
+}"
+   [(set_attr "length" "14")]
+)
 
 ;
 ; floatsidf2 instruction pattern(s).
@@ -1571,7 +1838,9 @@ check_label_emit ();
   CC_STATUS_INIT;
   mvs_check_page (0, 16, 8);
   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).
@@ -1586,11 +1855,13 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LRER        %0,%1\";
-}")
+}"
+   [(set_attr "length" "2")]
+)
 
 ;
 ; extendsfdf2 instruction pattern(s).
-;
+; 
 
 (define_insn "extendsfdf2"
   [(set (match_operand:DF 0 "general_operand" "=f")
@@ -1612,7 +1883,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"SDR %0,%0\;LE       %0,%1\";
-}")
+}"
+   [(set_attr "length" "10")]
+)
 
 ;;
 ;;- Add instructions.
@@ -1621,39 +1894,41 @@ check_label_emit ();
 ;
 ; adddi3 instruction pattern(s).
 ;
-
-(define_expand "adddi3"
-  [(set (match_operand:DI 0 "general_operand" "")
-       (plus:DI (match_operand:DI 1 "general_operand" "")
-                (match_operand:DI 2 "general_operand" "")))]
-  ""
-  "
-{
-  rtx label = gen_label_rtx ();
-  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
-  rtx op0_low = gen_lowpart (SImode, operands[0]);
-       
-  emit_insn (gen_rtx (SET, VOIDmode, op0_high,
-                   gen_rtx (PLUS, SImode,
-                           operand_subword (operands[1], 0, 1, DImode),
-                           operand_subword (operands[2], 0, 1, DImode))));
-  emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
-             gen_rtx (SET, VOIDmode, op0_low,
-                     gen_rtx (PLUS, SImode, gen_lowpart (SImode, operands[1]),
-                             gen_lowpart (SImode, operands[2]))),
-             gen_rtx (USE, VOIDmode, gen_rtx (LABEL_REF, VOIDmode, label)))));
-  emit_insn (gen_rtx (SET, VOIDmode, op0_high,
-                   gen_rtx (PLUS, SImode, op0_high,
-                           GEN_INT (1))));
-  emit_label (label);
-  DONE;
-}")
+;
+;(define_expand "adddi3"
+;  [(set (match_operand:DI 0 "general_operand" "")
+;      (plus:DI (match_operand:DI 1 "general_operand" "")
+;               (match_operand:DI 2 "general_operand" "")))]
+;  ""
+;  "
+;{
+;  rtx label = gen_label_rtx ();
+;  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
+;  rtx op0_low = gen_lowpart (SImode, operands[0]);
+;      
+;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
+;                  gen_rtx_PLUS (SImode,
+;                          operand_subword (operands[1], 0, 1, DImode),
+;                          operand_subword (operands[2], 0, 1, DImode))));
+;  emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+;            gen_rtx_SET (VOIDmode, op0_low,
+;                    gen_rtx_PLUS (SImode, gen_lowpart (SImode, operands[1]),
+;                            gen_lowpart (SImode, operands[2]))),
+;            gen_rtx_USE (VOIDmode, gen_rtx_LABEL_REF (VOIDmode, label)))));
+;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
+;                  gen_rtx_PLUS (SImode, op0_high,
+;                          gen_rtx_CONST_INT (SImode, 1))));
+;  emit_label (label);
+;  DONE;
+;}")
 
 (define_insn ""
   [(set (match_operand:SI 0 "general_operand" "=d")
        (plus:SI (match_operand:SI 1 "general_operand" "%0")
                 (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 ();
       return \"AL      %0,%2\;L        14,=A(%l3)\;BCR 12,14\";
     }
   return \"AL  %0,%2\;BC       12,%l3\";
-}")
+}"
+   [(set_attr "length" "10")]
+)
 
 ;
 ; addsi3 instruction pattern(s).
@@ -1706,10 +1983,12 @@ 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);
   return \"LA  %0,%c2(,%1)\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ; This insn handles additions that are relative to the frame pointer.
 
@@ -1723,17 +2002,28 @@ check_label_emit ();
   check_label_emit ();
   if ((unsigned) INTVAL (operands[2]) < 4096)
     {
+      CC_STATUS_INIT;  /* add assumes CC but LA doesnt set CC */
       mvs_check_page (0, 4, 0);
       return \"LA      %0,%c2(,%1)\";
     }
   if (REGNO (operands[1]) == REGNO (operands[0]))
     {
+      CC_STATUS_INIT;
       mvs_check_page (0, 4, 0);
       return \"A       %0,%2\";
     }
   mvs_check_page (0, 6, 0);
   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"
   [(set (match_operand:SI 0 "general_operand" "=d")
@@ -1752,14 +2042,16 @@ check_label_emit ();
     {
       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);
          return \"BCTR %0,0\";
        }
     }
   mvs_check_page (0, 4, 0);
   return \"A   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; addhi3 instruction pattern(s).
@@ -1782,7 +2074,7 @@ check_label_emit ();
     {
       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);
          return \"BCTR %0,0\";
        }
@@ -1791,7 +2083,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"AH  %0,%2\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; addqi3 instruction pattern(s).
@@ -1805,12 +2099,14 @@ 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);
   if (REG_P (operands[2]))
     return \"LA        %0,0(%1,%2)\";
   return \"LA  %0,%B2(,%1)\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; adddf3 instruction pattern(s).
@@ -1831,7 +2127,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"AD  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; addsf3 instruction pattern(s).
@@ -1852,7 +2150,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"AE  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Subtract instructions.
@@ -1861,41 +2161,43 @@ check_label_emit ();
 ;
 ; subdi3 instruction pattern(s).
 ;
-
-(define_expand "subdi3"
-  [(set (match_operand:DI 0 "general_operand" "")
-       (minus:DI (match_operand:DI 1 "general_operand" "")
-                 (match_operand:DI 2 "general_operand" "")))]
-  ""
-  "
-{
-  rtx label = gen_label_rtx ();
-  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
-  rtx op0_low = gen_lowpart (SImode, operands[0]);
-       
-  emit_insn (gen_rtx (SET, VOIDmode, op0_high,
-                   gen_rtx (MINUS, SImode,
-                             operand_subword (operands[1], 0, 1, DImode),
-                             operand_subword (operands[2], 0, 1, DImode))));
-  emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
-                   gen_rtx (SET, VOIDmode, op0_low,
-                             gen_rtx (MINUS, SImode,
-                                     gen_lowpart (SImode, operands[1]),
-                                     gen_lowpart (SImode, operands[2]))),
-                   gen_rtx (USE, VOIDmode,
-                             gen_rtx (LABEL_REF, VOIDmode, label)))));
-  emit_insn (gen_rtx (SET, VOIDmode, op0_high,
-                     gen_rtx (MINUS, SImode, op0_high,
-                             GEN_INT (1))));
-  emit_label (label);
-  DONE;
-}")
+;
+;(define_expand "subdi3"
+;  [(set (match_operand:DI 0 "general_operand" "")
+;      (minus:DI (match_operand:DI 1 "general_operand" "")
+;                (match_operand:DI 2 "general_operand" "")))]
+;  ""
+;  "
+;{
+;  rtx label = gen_label_rtx ();
+;  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
+;  rtx op0_low = gen_lowpart (SImode, operands[0]);
+;      
+;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
+;                  gen_rtx_MINUS (SImode,
+;                            operand_subword (operands[1], 0, 1, DImode),
+;                            operand_subword (operands[2], 0, 1, DImode))));
+;  emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+;                  gen_rtx_SET (VOIDmode, op0_low,
+;                            gen_rtx_MINUS (SImode,
+;                                    gen_lowpart (SImode, operands[1]),
+;                                    gen_lowpart (SImode, operands[2]))),
+;                  gen_rtx_USE (VOIDmode,
+;                            gen_rtx_LABEL_REF (VOIDmode, label)))));
+;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
+;                    gen_rtx_MINUS (SImode, op0_high,
+;                            gen_rtx_CONST_INT (SImode, 1))));
+;  emit_label (label);
+;  DONE;
+;}")
 
 (define_insn ""
   [(set (match_operand:SI 0 "general_operand" "=d")
        (minus:SI (match_operand:SI 1 "general_operand" "0")
                  (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 ();
       return \"SL      %0,%2\;L        14,=A(%l3)\;BCR 12,14\";
     }
   return \"SL  %0,%2\;BC       12,%l3\";
-}")
+}"
+   [(set_attr "length" "10")]
+)
 
 ;
 ; subsi3 instruction pattern(s).
@@ -1950,13 +2254,15 @@ check_label_emit ();
     }
   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);
       return \"BCTR    %0,0\";
     }
   mvs_check_page (0, 4, 0);
   return \"S   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; subhi3 instruction pattern(s).
@@ -1977,7 +2283,7 @@ check_label_emit ();
     }
   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);
       return \"BCTR    %0,0\";
     }
@@ -1988,7 +2294,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"SH  %0,%2\";
-}")
+}"
+   [(set_attr "length" "8")]
+)
 
 ;
 ; subqi3 instruction pattern(s).
@@ -2003,13 +2311,13 @@ check_label_emit ();
 {
   if (REG_P (operands[2]))
     {
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (MINUS, QImode, operands[1], operands[2])));
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_MINUS (QImode, operands[1], operands[2])));
     }
   else
     {
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (PLUS, QImode, operands[1],
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_PLUS (QImode, operands[1],
                                 negate_rtx (QImode, operands[2]))));
     }
   DONE;
@@ -2023,10 +2331,11 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
-  CC_STATUS_INIT;
   mvs_check_page (0, 2, 0);
   return \"SR  %0,%2\";
-}")
+}"
+   [(set_attr "length" "2")]
+)
 
 ;
 ; subdf3 instruction pattern(s).
@@ -2047,7 +2356,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"SD  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; subsf3 instruction pattern(s).
@@ -2068,7 +2379,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"SE  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Multiply instructions.
@@ -2088,31 +2401,43 @@ check_label_emit ();
   if (GET_CODE (operands[1]) == CONST_INT
       && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
     {
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                         gen_rtx (MULT, SImode, operands[2], operands[1])));
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                         gen_rtx_MULT (SImode, operands[2], operands[1])));
     }
   else if (GET_CODE (operands[2]) == CONST_INT
           && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))
     {
-      emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                         gen_rtx (MULT, SImode, operands[1], operands[2])));
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                         gen_rtx_MULT (SImode, operands[1], operands[2])));
     }
   else
     {
       rtx r = gen_reg_rtx (DImode);
 
-      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)));
+      /* XXX trouble.  Below we generate some rtx's that model what
+       * is really supposed to happen with multiply on the 370/390
+       * hardware, and that is all well & god.  However, during optimization
+       * it can happen that the two operands are exchanged (after all, 
+       * multiplication is commutitive), in which case the doubleword
+       * 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;
 }")
 
 (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")
                 (match_operand:SI 2 "immediate_operand" "K")))]
   ""
@@ -2121,12 +2446,16 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 4, 0);
   return \"MH  %0,%H2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
+;; XXX see comments in mulsi above.
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=d")
-       (mult:DI (match_operand:DI 1 "general_operand" "%0")
-                (match_operand:SI 2 "general_operand" "g")))]
+       (mult:SI (match_operand:DI 1 "general_operand" "%0")
+;; XXX see above (match_operand:SI 2 "general_operand" "g")))]
+                (match_operand:SI 2 "general_operand" "di")))]
   ""
   "*
 {
@@ -2138,7 +2467,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"M   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; muldf3 instruction pattern(s).
@@ -2159,7 +2490,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"MD  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; mulsf3 instruction pattern(s).
@@ -2180,7 +2513,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"ME  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Divide instructions.
@@ -2200,10 +2535,10 @@ check_label_emit ();
   rtx r = gen_reg_rtx (DImode);
 
   emit_insn (gen_extendsidi2 (r, operands[1]));
-  emit_insn (gen_rtx (SET, VOIDmode, r,
-                       gen_rtx (DIV, SImode, r, operands[2])));
-  emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (SUBREG, SImode, r, 1)));
+  emit_insn (gen_rtx_SET (VOIDmode, r,
+                       gen_rtx_DIV (SImode, r, operands[2])));
+  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_SUBREG (SImode, r, 1)));
   DONE;
 }")
 
@@ -2220,8 +2555,8 @@ check_label_emit ();
   "
 {
   rtx dr = gen_reg_rtx (DImode);
-  rtx dr_0 = gen_rtx (SUBREG, SImode, dr, 0);
-  rtx dr_1 = gen_rtx (SUBREG, SImode, dr, 1);
+  rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
+  rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1);
 
 
   if (GET_CODE (operands[2]) == CONST_INT)
@@ -2229,18 +2564,18 @@ check_label_emit ();
       if (INTVAL (operands[2]) > 0)
        {
          emit_insn (gen_zero_extendsidi2 (dr, operands[1]));
-         emit_insn (gen_rtx (SET, VOIDmode, dr,
-                       gen_rtx (DIV, SImode, dr, operands[2])));
+         emit_insn (gen_rtx_SET (VOIDmode, dr,
+                       gen_rtx_DIV (SImode, dr, operands[2])));
        }
       else
        {
          rtx label1 = gen_label_rtx ();
 
-         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_0, operands[1]));
+         emit_insn (gen_rtx_SET (VOIDmode, dr_1, const0_rtx));
          emit_insn (gen_cmpsi (dr_0, operands[2]));
          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);
        }
     }
@@ -2251,28 +2586,29 @@ check_label_emit ();
       rtx label3 = gen_label_rtx ();
       rtx sr = gen_reg_rtx (SImode);
 
-      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, dr_1, const0_rtx));
+      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, dr_1, const0_rtx));
       emit_insn (gen_cmpsi (sr, dr_0));
       emit_jump_insn (gen_bgtu (label3));
       emit_insn (gen_cmpsi (sr, const1_rtx));
       emit_jump_insn (gen_blt (label2));
+      emit_insn (gen_cmpsi (sr, const1_rtx));
       emit_jump_insn (gen_beq (label1));
-      emit_insn (gen_rtx (SET, VOIDmode, dr,
-                         gen_rtx (LSHIFTRT, DImode, dr,
-                                   GEN_INT (32))));
-      emit_insn (gen_rtx (SET, VOIDmode, dr,
-                   gen_rtx (DIV, SImode, dr, sr)));
+      emit_insn (gen_rtx_SET (VOIDmode, dr,
+                         gen_rtx_LSHIFTRT (DImode, dr,
+                                   gen_rtx_CONST_INT (SImode, 32))));
+      emit_insn (gen_rtx_SET (VOIDmode, dr,
+                   gen_rtx_DIV (SImode, dr, sr)));
       emit_jump_insn (gen_jump (label3));
       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_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_insn (gen_rtx (SET, VOIDmode, operands[0], dr_1));
+  emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_1));
 
   DONE;
 }")
@@ -2281,8 +2617,8 @@ check_label_emit ();
 
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=d")
-       (div:DI (match_operand:DI 1 "register_operand" "0")
-               (match_operand:SI 2 "general_operand" "")))]
+       (div:SI (match_operand:DI 1 "register_operand" "0")
+               (match_operand:SI 2 "general_operand" "dm")))]
   ""
   "*
 {
@@ -2294,7 +2630,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"D   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; divdf3 instruction pattern(s).
@@ -2315,7 +2653,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"DD  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; divsf3 instruction pattern(s).
@@ -2336,7 +2676,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"DE  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Modulo instructions.
@@ -2356,10 +2698,10 @@ check_label_emit ();
   rtx r = gen_reg_rtx (DImode);
 
   emit_insn (gen_extendsidi2 (r, operands[1]));
-  emit_insn (gen_rtx (SET, VOIDmode, r,
-                       gen_rtx (MOD, SImode, r, operands[2])));
-  emit_insn (gen_rtx (SET, VOIDmode, operands[0],
-                       gen_rtx (SUBREG, SImode, r, 0)));
+  emit_insn (gen_rtx_SET (VOIDmode, r,
+                       gen_rtx_MOD (SImode, r, operands[2])));
+  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                       gen_rtx_SUBREG (SImode, r, 0)));
   DONE;
 }")
 
@@ -2375,32 +2717,32 @@ check_label_emit ();
   "
 {
   rtx dr = gen_reg_rtx (DImode);
-  rtx dr_0 = gen_rtx (SUBREG, SImode, dr, 0);
-  rtx dr_1 = gen_rtx (SUBREG, SImode, dr, 1);
+  rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
+  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 (INTVAL (operands[2]) > 0)
        {
-         emit_insn (gen_rtx (SET, VOIDmode, dr,
-                             gen_rtx (LSHIFTRT, DImode, dr,
-                                       GEN_INT (32))));
-         emit_insn (gen_rtx (SET, VOIDmode, dr,
-                       gen_rtx (MOD, SImode, dr, operands[2])));
+         emit_insn (gen_rtx_SET (VOIDmode, dr,
+                             gen_rtx_LSHIFTRT (DImode, dr,
+                                       gen_rtx_CONST_INT (SImode, 32))));
+         emit_insn (gen_rtx_SET (VOIDmode, dr,
+                       gen_rtx_MOD (SImode, dr, operands[2])));
        }
       else
        {
          rtx label1 = gen_label_rtx ();
          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_jump_insn (gen_bltu (label1));
-         emit_insn (gen_rtx (SET, VOIDmode, sr, gen_rtx (ABS, SImode, sr)));
-         emit_insn (gen_rtx (SET, VOIDmode, dr_0,
-                             gen_rtx (PLUS, SImode, dr_0, sr)));
+         emit_insn (gen_rtx_SET (VOIDmode, sr, gen_rtx_ABS (SImode, sr)));
+         emit_insn (gen_rtx_SET (VOIDmode, dr_0,
+                             gen_rtx_PLUS (SImode, dr_0, sr)));
          emit_label (label1);
        }
     }
@@ -2411,28 +2753,29 @@ check_label_emit ();
       rtx label3 = gen_label_rtx ();
       rtx sr = gen_reg_rtx (SImode);
 
-      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, dr_0, operands[1]));
+      emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
       emit_insn (gen_cmpsi (sr, dr_0));
       emit_jump_insn (gen_bgtu (label3));
       emit_insn (gen_cmpsi (sr, const1_rtx));
       emit_jump_insn (gen_blt (label2));
+      emit_insn (gen_cmpsi (sr, const1_rtx));
       emit_jump_insn (gen_beq (label1));
-      emit_insn (gen_rtx (SET, VOIDmode, dr,
-                         gen_rtx (LSHIFTRT, DImode, dr,
-                                   GEN_INT (32))));
-      emit_insn (gen_rtx (SET, VOIDmode, dr, gen_rtx (MOD, SImode, dr, sr)));
+      emit_insn (gen_rtx_SET (VOIDmode, dr,
+                         gen_rtx_LSHIFTRT (DImode, dr,
+                                   gen_rtx_CONST_INT (SImode, 32))));
+      emit_insn (gen_rtx_SET (VOIDmode, dr, gen_rtx_MOD (SImode, dr, sr)));
       emit_jump_insn (gen_jump (label3));
       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_label (label2);
-      emit_insn (gen_rtx (SET, VOIDmode, dr_0,
-                         gen_rtx (MINUS, SImode, dr_0, sr)));
+      emit_insn (gen_rtx_SET (VOIDmode, dr_0,
+                         gen_rtx_MINUS (SImode, dr_0, sr)));
       emit_label (label3);
 
     }
-  emit_insn (gen_rtx (SET, VOIDmode, operands[0], dr_0));
+  emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_0));
 
   DONE;
 }")
@@ -2441,8 +2784,8 @@ check_label_emit ();
 
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=d")
-       (mod:DI (match_operand:DI 1 "register_operand" "0")
-               (match_operand:SI 2 "general_operand" "")))]
+       (mod:SI (match_operand:DI 1 "register_operand" "0")
+               (match_operand:SI 2 "general_operand" "dm")))]
   ""
   "*
 {
@@ -2454,7 +2797,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"D   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- And instructions.
@@ -2494,6 +2839,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* and sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2504,10 +2850,11 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"N       %0,%2\";
     }
-  CC_STATUS_INIT;
   mvs_check_page (0, 6, 0);
   return \"NC  %O0(4,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "andsi3"
   [(set (match_operand:SI 0 "general_operand" "=d")
@@ -2517,6 +2864,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* and sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2524,7 +2872,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"N   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; andhi3 instruction pattern(s).
@@ -2538,6 +2888,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* and sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2545,10 +2896,12 @@ check_label_emit ();
     }
   if (REG_P (operands[0]))
     {
+      /* %K2 == sign extend operand to 32 bits so that CH works */
       mvs_check_page (0, 4, 0);
+      if (GET_CODE (operands[2]) == CONST_INT)
+         return \"N    %0,%K2\";
       return \"N       %0,%2\";
     }
-  CC_STATUS_INIT;
   if (GET_CODE (operands[2]) == CONST_INT)
     {
       mvs_check_page (0, 6, 0);
@@ -2556,7 +2909,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"NC  %O0(2,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "general_operand" "=d")
@@ -2566,14 +2921,18 @@ 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)
     {
+      /* %K2 == sign extend operand to 32 bits so that CH works */
       mvs_check_page (0, 4, 0);
-      return \"N       %0,%2\";
+      return \"N       %0,%K2\";
     }
   mvs_check_page (0, 2, 0);
   return \"NR  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; andqi3 instruction pattern(s).
@@ -2587,7 +2946,7 @@ 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]))
     {
       mvs_check_page (0, 2, 0);
@@ -2605,7 +2964,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"NC  %O0(1,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "andqi3"
   [(set (match_operand:QI 0 "general_operand" "=d")
@@ -2615,7 +2976,7 @@ 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)
     {
       mvs_check_page (0, 4, 0);
@@ -2623,7 +2984,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 2, 0);
   return \"NR  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Bit set (inclusive or) instructions.
@@ -2663,6 +3026,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2673,10 +3037,11 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"O       %0,%2\";
     }
-  CC_STATUS_INIT;
   mvs_check_page (0, 6, 0);
   return \"OC  %O0(4,%R0),%2\";
-}")
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn "iorsi3"
   [(set (match_operand:SI 0 "general_operand" "=d")
@@ -2686,6 +3051,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2693,7 +3059,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"O   %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; iorhi3 instruction pattern(s).
@@ -2707,6 +3075,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2717,7 +3086,6 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"O       %0,%2\";
     }
-  CC_STATUS_INIT;
   if (GET_CODE (operands[2]) == CONST_INT)
     {
       mvs_check_page (0, 6, 0);
@@ -2725,7 +3093,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"OC  %O0(2,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "general_operand" "=d")
@@ -2735,6 +3105,7 @@ 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)
     {
       mvs_check_page (0, 4, 0);
@@ -2742,7 +3113,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 2, 0);
   return \"OR  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;
 ; iorqi3 instruction pattern(s).
@@ -2756,7 +3129,7 @@ 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]))
     {
       mvs_check_page (0, 2, 0);
@@ -2767,7 +3140,6 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"O       %0,%2\";
     }
-  CC_STATUS_INIT;
   if (GET_CODE (operands[2]) == CONST_INT)
     {
       mvs_check_page (0, 4, 0);
@@ -2775,7 +3147,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"OC  %O0(1,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "iorqi3"
   [(set (match_operand:QI 0 "general_operand" "=d")
@@ -2785,7 +3159,7 @@ 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)
     {
       mvs_check_page (0, 4, 0);
@@ -2793,7 +3167,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 2, 0);
   return \"OR  %0,%2\";
-}")
+}"
+   [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Xor instructions.
@@ -2833,6 +3209,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2843,10 +3220,11 @@ check_label_emit ();
       mvs_check_page (0, 4, 0);
       return \"X       %0,%2\";
     }
-  CC_STATUS_INIT;
   mvs_check_page (0, 6, 0);
   return \"XC  %O0(4,%R0),%2\";
-}")
+}"
+   [(set_attr "length" "6")]
+)
 
 (define_insn "xorsi3"
   [(set (match_operand:SI 0 "general_operand" "=d")
@@ -2856,6 +3234,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2863,7 +3242,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"X   %0,%2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; xorhi3 instruction pattern(s).
@@ -2877,6 +3258,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   if (REG_P (operands[2]))
     {
       mvs_check_page (0, 2, 0);
@@ -2885,9 +3267,8 @@ check_label_emit ();
   if (REG_P (operands[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)
     {
       mvs_check_page (0, 6, 0);
@@ -2895,7 +3276,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"XC  %O0(2,%R0),%2\";
-}")
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn "xorhi3"
   [(set (match_operand:HI 0 "general_operand" "=d")
@@ -2905,14 +3288,17 @@ 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)
     {
       mvs_check_page (0, 4, 0);
-      return \"X       %0,%2\";
+      return \"X       %0,%H2\";
     }
   mvs_check_page (0, 2, 0);
   return \"XR  %0,%2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; xorqi3 instruction pattern(s).
@@ -2926,7 +3312,7 @@ 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]))
     {
       mvs_check_page (0, 2, 0);
@@ -2944,7 +3330,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 6, 0);
   return \"XC  %O0(1,%R0),%2\";
-}")
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn "xorqi3"
   [(set (match_operand:QI 0 "general_operand" "=d")
@@ -2954,7 +3342,7 @@ 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)
     {
       mvs_check_page (0, 4, 0);
@@ -2962,7 +3350,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 2, 0);
   return \"XR  %0,%2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Negate instructions.
@@ -2981,7 +3371,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LCR %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;
 ; neghi2 instruction pattern(s).
@@ -2996,7 +3388,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 10, 0);
   return \"SLL %1,16\;SRA      %1,16\;LCR      %0,%1\";
-}")
+}"
+  [(set_attr "length" "10")]
+)
 
 ;
 ; negdf2 instruction pattern(s).
@@ -3011,7 +3405,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LCDR        %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;
 ; negsf2 instruction pattern(s).
@@ -3026,7 +3422,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LCER        %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;;
 ;;- Absolute value instructions.
@@ -3045,7 +3443,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LPR %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;
 ; abshi2 instruction pattern(s).
@@ -3060,7 +3460,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 10, 0);
   return \"SLL %1,16\;SRA      %1,16\;LPR      %0,%1\";
-}")
+}"
+  [(set_attr "length" "10")]
+)
 
 ;
 ; absdf2 instruction pattern(s).
@@ -3075,7 +3477,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LPDR        %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;
 ; abssf2 instruction pattern(s).
@@ -3090,7 +3494,9 @@ check_label_emit ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LPER        %0,%1\";
-}")
+}"
+  [(set_attr "length" "2")]
+)
 
 ;;
 ;;- One complement instructions.
@@ -3126,6 +3532,7 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   if (REG_P (operands[0]))
     {
       mvs_check_page (0, 4, 4);
@@ -3134,7 +3541,9 @@ check_label_emit ();
   CC_STATUS_INIT;
   mvs_check_page (0, 6, 4);
   return \"XC  %O0(4,%R0),=F'-1'\";
-}")
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn "one_cmplsi2"
   [(set (match_operand:SI 0 "general_operand" "=d")
@@ -3143,9 +3552,12 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   mvs_check_page (0, 4, 4);
   return \"X   %0,=F'-1'\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; one_cmplhi2 instruction pattern(s).
@@ -3158,15 +3570,17 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   if (REG_P (operands[0]))
     {
       mvs_check_page (0, 4, 4);
       return \"X       %0,=F'-1'\";
     }
-  CC_STATUS_INIT;
   mvs_check_page (0, 6, 4);
   return \"XC  %O0(2,%R0),=X'FFFF'\";
-}")
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn "one_cmplhi2"
   [(set (match_operand:HI 0 "general_operand" "=d")
@@ -3175,9 +3589,12 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
   mvs_check_page (0, 4, 4);
   return \"X   %0,=F'-1'\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; one_cmplqi2 instruction pattern(s).
@@ -3190,7 +3607,7 @@ 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]))
     {
       mvs_check_page (0, 4, 4);
@@ -3198,7 +3615,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 4, 0);
   return \"XI  %0,255\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 (define_insn "one_cmplqi2"
   [(set (match_operand:QI 0 "general_operand" "=d")
@@ -3207,10 +3626,12 @@ 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);
   return \"X   %0,=F'-1'\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;;
 ;;- Arithmetic shift instructions.
@@ -3228,12 +3649,16 @@ 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);
   if (REG_P (operands[2]))
     return \"SLDA      %0,0(%2)\";
   return \"SLDA        %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; ashrdi3 instruction pattern(s).
@@ -3247,11 +3672,16 @@ 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);
   if (REG_P (operands[2])) 
     return \"SRDA      %0,0(%2)\";
   return \"SRDA        %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; ashlsi3 instruction pattern(s).
@@ -3265,12 +3695,13 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
-  CC_STATUS_INIT;
   mvs_check_page (0, 4, 0);
   if (REG_P (operands[2])) 
     return \"SLL       %0,0(%2)\";
   return \"SLL %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; ashrsi3 instruction pattern(s).
@@ -3284,11 +3715,14 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
+  CC_STATUS_SET (operands[0], operands[1]);
   mvs_check_page (0, 4, 0);
   if (REG_P (operands[2])) 
     return \"SRA       %0,0(%2)\";
   return \"SRA %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; ashlhi3 instruction pattern(s).
@@ -3306,7 +3740,9 @@ check_label_emit ();
   if (REG_P (operands[2])) 
     return \"SLL       %0,16(%2)\;SRA  %0,16\";
   return \"SLL %0,16+%c2\;SRA  %0,16\";
-}")
+}"
+  [(set_attr "length" "8")]
+)
 
 ;
 ; ashrhi3 instruction pattern(s).
@@ -3320,11 +3756,13 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
-  mvs_check_page (0, 4, 0);
+  mvs_check_page (0, 8, 0);
   if (REG_P (operands[2])) 
     return \"SLL       %0,16\;SRA      %0,16(%2)\";
   return \"SLL %0,16\;SRA      %0,16+%c2\";
-}")
+}"
+  [(set_attr "length" "8")]
+)
 
 ;
 ; ashlqi3 instruction pattern(s).
@@ -3338,12 +3776,13 @@ check_label_emit ();
   "*
 {
   check_label_emit ();
-  CC_STATUS_INIT;
   mvs_check_page (0, 4, 0);
   if (REG_P (operands[2])) 
     return \"SLL       %0,0(%2)\";
   return \"SLL %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; ashrqi3 instruction pattern(s).
@@ -3361,7 +3800,9 @@ check_label_emit ();
   if (REG_P (operands[2])) 
     return \"SLL       %0,24\;SRA      %0,24(%2)\";
   return \"SLL %0,24\;SRA      %0,24+%c2\";
-}")
+}"
+  [(set_attr "length" "8")]
+)
 
 ;;
 ;;- Logical shift instructions.
@@ -3383,7 +3824,9 @@ check_label_emit ();
   if (REG_P (operands[2])) 
     return \"SRDL      %0,0(%2)\";
   return \"SRDL        %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 
 ;
@@ -3402,7 +3845,9 @@ check_label_emit ();
   if (REG_P (operands[2])) 
     return \"SRL       %0,0(%2)\";
   return \"SRL %0,%c2\";
-}")
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; lshrhi3 instruction pattern(s).
@@ -3416,7 +3861,7 @@ 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]))
     {
       mvs_check_page (0, 8, 4);
@@ -3424,7 +3869,9 @@ check_label_emit ();
     }
   mvs_check_page (0, 8, 4);
   return \"N   %0,=X'0000FFFF'\;SRL    %0,%c2\";
-}")
+}"
+  [(set_attr "length" "8")]
+)
 
 ;
 ; lshrqi3 instruction pattern(s).
@@ -3438,16 +3885,18 @@ 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);
   if (REG_P (operands[2])) 
     return \"N %0,=X'000000FF'\;SRL    %0,0(%2)\";
   return \"N   %0,=X'000000FF'\;SRL    %0,%c2\";
-}")
+}"
+  [(set_attr "length" "8")]
+)
 
-;;
+;; =======================================================================
 ;;- Conditional jump instructions.
-;;
+;; =======================================================================
 
 ;
 ; beq instruction pattern(s).
@@ -3458,23 +3907,23 @@ check_label_emit ();
        (if_then_else (eq (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BER 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BER 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BE      %l0\";
     }
-  return \"BE  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BER 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bne instruction pattern(s).
@@ -3485,23 +3934,23 @@ check_label_emit ();
        (if_then_else (ne (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNER        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNER        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNE     %l0\";
     }
-  return \"BNE %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNER        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bgt instruction pattern(s).
@@ -3512,23 +3961,23 @@ check_label_emit ();
        (if_then_else (gt (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BH      %l0\";
     }
-  return \"BH  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BHR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bgtu instruction pattern(s).
@@ -3539,23 +3988,23 @@ check_label_emit ();
        (if_then_else (gtu (cc0)
                           (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BH      %l0\";
     }
-  return \"BH  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BHR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; blt instruction pattern(s).
@@ -3566,23 +4015,23 @@ check_label_emit ();
        (if_then_else (lt (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BL      %l0\";
     }
-  return \"BL  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BLR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bltu instruction pattern(s).
@@ -3593,23 +4042,23 @@ check_label_emit ();
        (if_then_else (ltu (cc0)
                           (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BL      %l0\";
     }
-  return \"BL  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BLR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bge instruction pattern(s).
@@ -3620,23 +4069,23 @@ check_label_emit ();
        (if_then_else (ge (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNL     %l0\";
     }
-  return \"BNL %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNLR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bgeu instruction pattern(s).
@@ -3647,23 +4096,23 @@ check_label_emit ();
        (if_then_else (geu (cc0)
                           (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNL     %l0\";
     }
-  return \"BNL %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNLR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; ble instruction pattern(s).
@@ -3674,23 +4123,23 @@ check_label_emit ();
        (if_then_else (le (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNH     %l0\";
     }
-  return \"BNH %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNHR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; bleu instruction pattern(s).
@@ -3701,23 +4150,23 @@ check_label_emit ();
        (if_then_else (leu (cc0)
                           (const_int 0))
                      (label_ref (match_operand 0 "" ""))
-                     (pc)))]
+                     (pc)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNH     %l0\";
     }
-  return \"BNH %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNHR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;;
 ;;- Negated conditional jump instructions.
@@ -3728,234 +4177,235 @@ check_label_emit ();
        (if_then_else (eq (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNER        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNER        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNE     %l0\";
     }
-  return \"BNE %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNER        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (ne (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BER 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BER 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BE      %l0\";
     }
-  return \"BE  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BER 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (gt (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNH     %l0\";
     }
-  return \"BNH %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNHR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (gtu (cc0)
                           (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNHR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNH     %l0\";
     }
-  return \"BNH %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNHR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (lt (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNL     %l0\";
     }
-  return \"BNL %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNLR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (ltu (cc0)
                           (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BNLR        14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BNL     %l0\";
     }
-  return \"BNL %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BNLR        14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (ge (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BL      %l0\";
     }
-  return \"BL  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BLR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (geu (cc0)
                           (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BLR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BL      %l0\";
     }
-  return \"BL  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BLR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (le (cc0)
                          (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BH      %l0\";
     }
-  return \"BH  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BHR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
        (if_then_else (leu (cc0)
                           (const_int 0))
                      (pc)
-                     (label_ref (match_operand 0 "" ""))))]
+                     (label_ref (match_operand 0 "" ""))))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
-    }
-  if (mvs_check_page (0, 4, 0))
-    {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BHR 14\";
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
+    { 
+      return \"BH      %l0\";
     }
-  return \"BH  %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BHR 14\";
+}"
+  [(set_attr "length" "6")]
+)
 
-;;
+;; ==============================================================
 ;;- 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 ""
   [(set (pc)
@@ -3967,23 +4417,23 @@ check_label_emit ();
         (pc)))
    (set (match_dup 0)
        (plus:SI (match_dup 0)
-                (const_int -1)))]
+                (const_int -1)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l1)\;BCTR        %0,14\";
-    }
-  if (mvs_check_page (0, 4, 0))
+  mvs_check_page (0, 4, 0);
+  if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
     {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l1)\;BCTR        %0,14\";
+      return \"BCT     %0,%l1\";
     }
-  return \"BCT %0,%l1\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l1)\;BCTR        %0,14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 (define_insn ""
   [(set (pc)
@@ -3995,25 +4445,25 @@ check_label_emit ();
         (label_ref (match_operand 1 "" ""))))
    (set (match_dup 0)
        (plus:SI (match_dup 0)
-                (const_int -1)))]
+                (const_int -1)))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l1)\;BCTR        %0,14\";
-    }
-  if (mvs_check_page (0, 4, 0))
+  mvs_check_page (0, 4, 0);
+  if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
     {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l1)\;BCTR        %0,14\";
+      return \"BCT     %0,%l1\";
     }
-  return \"BCT %0,%l1\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l1)\;BCTR        %0,14\";
+}"
+  [(set_attr "length" "6")]
+)
 
-;;
+;; =============================================================
 ;;- Unconditional jump instructions.
 ;;
 
@@ -4023,37 +4473,44 @@ check_label_emit ();
 
 (define_insn "jump"
   [(set (pc)
-       (label_ref (match_operand 0 "" "")))]
+       (label_ref (match_operand 0 "" "")))
+;   (clobber (reg:SI 14))
+   ]
   ""
   "*
 {
   check_label_emit ();
-  if (!mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
-    {
-      mvs_check_page (0, 6, 4);
-      return \"L       14,=A(%l0)\;BR  14\";
-    }
-  if (mvs_check_page (0, 4, 0))
+  mvs_check_page (0, 4, 0);
+  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
     {
-      mvs_check_page (0, 2, 4);
-      return \"L       14,=A(%l0)\;BR  14\";
+      return \"B       %l0\";
     }
-  return \"B   %l0\";
-}")
+  mvs_check_page (0, 2, 4);
+  return \"L   14,=A(%l0)\;BR  14\";
+}"
+  [(set_attr "length" "6")]
+)
 
 ;
 ; indirect-jump instruction pattern(s).
-;
+; hack alert -- should check that displacement is < 4096
 
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:SI 0 "general_operand" "r"))]
-  "(GET_CODE (operands[0]) != MEM )"
+  [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
+  ""
   "*
 {
   check_label_emit ();
-  mvs_check_page (0, 2, 0);
-  return \"BR  %0\";
-}")
+  if (REG_P (operands[0]))
+    {
+      mvs_check_page (0, 2, 0);
+      return \"BR      %0\";
+    }
+  mvs_check_page (0, 4, 0);
+  return \"B   %0\";
+}"
+  [(set_attr "length" "4")]
+)
 
 ;
 ; tablejump instruction pattern(s).
@@ -4062,7 +4519,9 @@ check_label_emit ();
 (define_insn "tablejump"
   [(set (pc)
        (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 ();
     }
   mvs_check_page (0, 10, 0);
   return \"L   14,%0\;BR       14\;DS  0F\";
-}")
+}"
+  [(set_attr "length" "10")]
+)
 
 ;;
 ;;- Jump to subroutine.
@@ -4082,34 +4543,55 @@ check_label_emit ();
 ;; 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.
 ;;
+;; 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).
 ;
+; 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"
   [(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];
   int i = STACK_POINTER_OFFSET;
+  CC_STATUS_INIT;
 
   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)))
     {
       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 );
     }
   else
     {
       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;
-}")
+#endif
+}"
+  [(set_attr "length" "22")]
+)
 
 ;
 ; call_value instruction pattern(s).
@@ -4118,38 +4600,57 @@ check_label_emit ();
 (define_insn "call_value"
   [(set (match_operand 0 "" "rf")
        (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];
   int i = STACK_POINTER_OFFSET;
+  CC_STATUS_INIT;
 
   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)))
     {
       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 );
     }
   else
     {
       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;
-}")
+#endif
+}"
+  [(set_attr "length" "22")]
+)
 
 (define_insn ""
   [(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"
   "*
 {
   static char temp[128];
   int i = STACK_POINTER_OFFSET;
+  CC_STATUS_INIT;
 
   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)))
     {
       mvs_check_page (0, 22, 4);
@@ -4162,19 +4663,30 @@ check_label_emit ();
       sprintf ( temp, \"LA     1,%d(,13)\;L    15,%%0\;BALR    14,15\", i );
     }
   return temp;
-}")
+#endif
+}"
+  [(set_attr "length" "22")]
+)
 
 (define_insn ""
   [(set (match_operand 0 "" "rf")
        (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"
   "*
 {
   static char temp[128];
   int i = STACK_POINTER_OFFSET;
+  CC_STATUS_INIT;
 
   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)))
     {
       mvs_check_page (0, 22, 4);
@@ -4187,6 +4699,44 @@ check_label_emit ();
       sprintf ( temp, \"LA     1,%d(,13)\;L    15,%%1\;BALR    14,15\", i );
     }
   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 ();
   check_label_emit ();
   mvs_check_page (0, 2, 0);
   return \"LR  0,0\";
-}")
-
+}"
+  [(set_attr "length" "2")]
+)
diff --git a/gcc/config/i370/linux.h b/gcc/config/i370/linux.h
new file mode 100644 (file)
index 0000000..5715909
--- /dev/null
@@ -0,0 +1,128 @@
+/* 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 */
diff --git a/gcc/config/i370/mvs.h b/gcc/config/i370/mvs.h
new file mode 100644 (file)
index 0000000..191be38
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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"
+
diff --git a/gcc/config/i370/oe.h b/gcc/config/i370/oe.h
new file mode 100644 (file)
index 0000000..6290052
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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"
+
diff --git a/gcc/config/i370/t-linux b/gcc/config/i370/t-linux
new file mode 100644 (file)
index 0000000..12cd6b8
--- /dev/null
@@ -0,0 +1,4 @@
+# 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 =
diff --git a/gcc/config/i370/t-mvs b/gcc/config/i370/t-mvs
new file mode 100644 (file)
index 0000000..d20ab38
--- /dev/null
@@ -0,0 +1,4 @@
+# There is no libgcc for mvs
+LIBGCC =
+INSTALL_LIBGCC =
+LIBGCC1_TEST =
diff --git a/gcc/config/i370/t-oe b/gcc/config/i370/t-oe
new file mode 100644 (file)
index 0000000..622402d
--- /dev/null
@@ -0,0 +1,4 @@
+# There is no libgcc for OpenEdition
+LIBGCC =
+INSTALL_LIBGCC =
+LIBGCC1_TEST =
diff --git a/gcc/config/i370/x-oe b/gcc/config/i370/x-oe
new file mode 100644 (file)
index 0000000..79f34bd
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# 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
+
diff --git a/gcc/config/i370/xm-linux.h b/gcc/config/i370/xm-linux.h
new file mode 100644 (file)
index 0000000..e0ab373
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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
+
diff --git a/gcc/config/i370/xm-mvs.h b/gcc/config/i370/xm-mvs.h
new file mode 100644 (file)
index 0000000..d764eb3
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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
+
diff --git a/gcc/config/i370/xm-oe.h b/gcc/config/i370/xm-oe.h
new file mode 100644 (file)
index 0000000..22e7bfa
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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
+