gcc S/390 backend 2

Hartmut Penner hp@zuck175192.boeblingen.de.ibm.com
Sun Oct 15 23:07:00 GMT 2000


Here are the reworked S/390 backend patches Part 2

	Hartmut Penner

diff -u -r --new-file egcs-20001002/gcc/config/s390/s390.c egcs-20001002-s390/gcc/config/s390/s390.c
--- egcs-20001002/gcc/config/s390/s390.c	Thu Jan  1 01:00:00 1970
+++ egcs-20001002-s390/gcc/config/s390/s390.c	Fri Oct 13 15:07:33 2000
@@ -0,0 +1,1093 @@
+/* Subroutines used for code generation on IBM S/390
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Hartmut Penner (hpenner@de.ibm.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.  */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "math.h"
+#include "obstack.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+
+
+#include "tm.h"
+#include "tm_p.h"
+
+extern int reload_completed;
+
+/* Function count for creating unique internal labels in a compile unit.  */
+int  s390_function_count = 0;
+
+
+/* Update the condition code from the insn.  Look mostly at the first
+   byte of the machine-specific insn description information.
+  
+   cc_state.value[12] refer to two possible values that might correspond
+   to the CC.  We only store register values.  */
+
+void
+update_cc (rtx body, rtx insn)
+{
+
+  if (GET_CODE (body) == PARALLEL)
+    body = XVECEXP (body, 0, 0);		
+
+  switch (get_attr_cc (insn))
+    {
+    case CC_NONE:
+      /* Insn does not affect the CC at all.  */
+      break;
+
+    case CC_CHANGE0:
+      /* Insn doesn't affect the CC but does modify operand[0], known to be
+         a register.  */
+      if (cc_status.value1 != 0
+          && reg_overlap_mentioned_p (XEXP (body, 0), cc_status.value1))
+        cc_status.value1 = 0;
+
+      if (cc_status.value2 != 0
+          && reg_overlap_mentioned_p (XEXP (body, 0), cc_status.value2))
+        cc_status.value2 = 0;
+
+      break;
+
+    case CC_CLOBBER:
+      /* Insn clobbers CC.  */
+      CC_STATUS_INIT;
+      break;
+
+    case CC_SETS:
+      /* Insn sets CC to recog_operand[0], but overflow is impossible.  */
+      CC_STATUS_INIT;
+      cc_status.flags |= CC_NO_OVERFLOW;
+      cc_status.value1 = XEXP (body, 0);
+      break;
+
+    case CC_SETS_OV:
+      /* Insn sets CC to recog_operand[0], but overflow is possible.  */
+      CC_STATUS_INIT;
+      cc_status.value1 = XEXP (body, 0);
+      break;
+
+   case CC_COMPARE:
+      /* Insn is a compare which sets the CC fully.  Update CC_STATUS for this
+         compare and mark whether the test will be signed or unsigned.  */
+      {
+        register rtx p = PATTERN (insn);
+
+        CC_STATUS_INIT;
+
+        if (GET_CODE (p) == PARALLEL)
+          p = XVECEXP (p, 0, 0);
+        cc_status.value1 = SET_SRC (p);
+
+        if (GET_CODE (SET_SRC (p)) == REG)
+          cc_status.flags |= CC_NO_OVERFLOW;
+      }
+      break;
+
+    default:
+      abort ();
+   }
+}
+
+/* Map for smallest class containing reg regno.  */
+
+enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
+{ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
+  ADDR_REGS,    ADDR_REGS, ADDR_REGS, ADDR_REGS,
+  ADDR_REGS,    ADDR_REGS, ADDR_REGS, ADDR_REGS,
+  ADDR_REGS,    ADDR_REGS, ADDR_REGS, ADDR_REGS,
+#ifdef IEEE_FLOAT
+  FP_REGS,      FP_REGS, FP_REGS, FP_REGS,
+  FP_REGS,      FP_REGS, FP_REGS, FP_REGS,
+  FP_REGS,      FP_REGS, FP_REGS, FP_REGS,
+#endif
+  FP_REGS,      FP_REGS, FP_REGS, FP_REGS,
+  ADDR_REGS
+};
+
+
+
+/* Return 1 if OP needs base and index register.  */
+
+static int 
+base_n_index_p (rtx op)
+{
+  if ((GET_CODE (op) == PLUS) &&
+      (GET_CODE (XEXP (op, 0)) == PLUS ||
+       GET_CODE (XEXP (op, 1)) == PLUS ||
+       GET_CODE (XEXP (op, 1)) == REG ))
+    return 1;
+  return 0;
+}
+
+/* Check mode and mode of op, set it to mode of op, if VOIDmode.  */ 
+
+static int
+check_mode (op, mode)
+     register rtx op;
+     enum machine_mode *mode;
+{
+  if (*mode == VOIDmode)
+      *mode = GET_MODE (op);
+  else
+  {
+    if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode)
+       return 0;
+  }
+  return 1;
+}
+
+/* Return 1 if valid general operand for a Pmode instruction
+   OP is the current operation.
+   MODE is the current operation mode.  */
+
+int
+general_pmode_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  rtx sym;
+  register enum rtx_code code = GET_CODE (op);
+
+  if (! check_mode (op, &mode))
+    return 0;
+
+  if (! flag_pic)
+     return general_operand (op, mode);
+  if ((flag_pic == 1) && code == SYMBOL_REF)
+    return 1;
+  if (code == SYMBOL_REF ||
+      code == LABEL_REF ||
+      code == CONST)
+    return 0;
+  if (code == MEM && GET_CODE (XEXP (op, 0)) == SYMBOL_REF &&
+      CONSTANT_POOL_ADDRESS_P (XEXP (op, 0))) 
+    {
+      sym = get_pool_constant (XEXP (op, 0));
+      if (GET_CODE (sym) == CONST ||
+	  GET_CODE (sym) == LABEL_REF ||
+	  ( GET_CODE (sym) == SYMBOL_REF &&
+	    (! SYMBOL_REF_FLAG (sym) ||
+	     (flag_pic>1))))
+	return 0;
+    }
+  return general_operand (op, mode);
+}
+
+/* Return 1 if OP is a valid FP-Register.
+   OP is the current operation.
+   MODE is the current operation mode.  */
+
+int
+fp_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+  if (! check_mode (op, &mode))
+    return 0;
+  if (code == REG && REGNO_OK_FOR_FP_P (REGNO (op)))
+    return 1;
+  else
+    return 0;
+}
+
+/* Return 1 if OP is a valid S operand for an RS, SI or SS type instruction.  */
+
+int
+s_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+
+  if (! check_mode (op,&mode))
+    return 0;
+
+  if (code == MEM) {
+    if (base_n_index_p (XEXP (op, 0)))
+      return 0;
+  }
+
+  return memory_operand (op, mode);
+}
+
+/* Return 1 if OP is a valid R or S operand for an RS, SI or SS type
+   instruction.  */
+
+int
+r_or_s_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+
+  if (!general_pmode_operand (op, mode))
+    return 0;
+
+  if (code == MEM) {
+    if (base_n_index_p (XEXP (op, 0)))
+      return 0;
+    else
+      return memory_operand (op, mode);
+  }
+  return register_operand (op, mode);
+}
+
+/* Return 1 if OP is a valid R or S or immediate operand for 
+   RS, SI or SS type instruction.  */
+
+int
+r_or_s_or_im8_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+
+  if (!general_pmode_operand (op, mode))
+    return 0;
+
+  if (code == MEM) {
+    if (base_n_index_p (XEXP (op, 0)))
+      return 0;
+    else
+      return memory_operand (op, mode);
+  }
+  return register_operand (op, mode) || immediate_operand (op, mode);
+}
+
+/* Return 1 if OP is a valid R or X or 16 bit immediate operand for 
+   RX, RR or RI type instruction.  */
+
+int
+r_or_x_or_im16_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+
+  if (! general_pmode_operand (op, mode))
+    return 0;
+
+  if (GET_CODE (op) == CONST_INT)
+    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'));
+  return register_operand (op, mode) || memory_operand (op, mode);
+}
+
+/* Return 1 if OP is a valid R or 8 bit immediate operand for 
+   !!!!!!! type instruction.  */
+
+int
+r_or_im8_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+
+  if (!general_pmode_operand (op, mode))
+    return 0;
+
+  if (GET_CODE (op) == CONST_INT)
+    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'));
+  return register_operand (op, mode) || memory_operand (op, mode);
+}
+
+
+/* Return 1 if valid operand for LA 
+   OP is the current operation.
+   MODE is the current operation mode.  */
+
+int
+la_address_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+  int reg;
+
+  if (code == PLUS &&
+      GET_CODE (XEXP (op, 0)) == PLUS &&
+      (( GET_CODE (XEXP (XEXP (op, 0), 0)) == REG &&
+	((reg = REGNO (XEXP (XEXP (op, 0), 0))) == STACK_POINTER_REGNUM ||
+	(reg == BASE_REGISTER))) ||	 
+      ( GET_CODE (XEXP (XEXP (op, 0), 1)) == REG &&
+	((reg = REGNO (XEXP (XEXP (op, 0), 1))) == STACK_POINTER_REGNUM ||
+	(reg == BASE_REGISTER)))))
+    return address_operand (op, mode);
+  else 
+     return 0;
+}
+
+/* Return 1 if valid operand for BRAS
+   OP is the current operation.
+   MODE is the current operation mode.  */
+
+int
+bras_sym_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  register enum rtx_code code = GET_CODE (op);
+
+  return (code == SYMBOL_REF);
+}
+
+int
+dead_p (rtx insn, rtx x)
+{
+  rtx link;
+  unsigned int regno;
+  regno = REGNO (x);
+
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+  {
+      if (REG_NOTE_KIND (link) != REG_DEAD || GET_CODE (XEXP (link, 0)) != REG)
+        continue;
+
+      if (regno == REGNO (XEXP (link, 0)))
+          return 1;
+  }
+  return 0;
+}
+
+/* Return 1 if the next instruction is an unsigned jump instruction.
+    INSN is the current instruction.
+   There are still problems left:
+     if an branch equal is followed by an branch unsigned gt (lt)
+     the signed compare is taken and the branch unsigned could be
+     evaluated wrong. To avoid this, the branch (un)equal are
+     considered to clobber the cc. This will lead to a new compare
+     between the two cond. branches. The better solution would be
+     to take for the (un)equal branch the comparision of the
+     following branch. But the next_cc0_user fails with segmentation fault.  */
+
+int
+unsigned_comparison_operator (insn)
+     rtx insn;
+{
+  switch (GET_CODE (insn))
+    {
+    case GEU:
+    case GTU:
+    case LEU:
+    case LTU:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+int
+unsigned_jump_follows_p (insn)
+     rtx insn;
+{
+  if ( !(insn = next_cc0_user (insn)))
+    /*abort ()*/;
+  else if (GET_CODE (insn) == JUMP_INSN
+           && GET_CODE (PATTERN (insn)) == SET
+           && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
+    return unsigned_comparison_operator (XEXP (SET_SRC (PATTERN (insn)), 0));
+  else if (GET_CODE (insn) == INSN
+           && GET_CODE (PATTERN (insn)) == SET)
+    return unsigned_comparison_operator (SET_SRC (PATTERN (insn)));
+  else
+    abort ();
+}
+static void
+output_branch_condition (FILE *file, rtx code)
+{
+  switch (GET_CODE (code)) {
+  case EQ:
+    fprintf (file, "E ");
+    break;
+  case NE:
+    fprintf (file, "NE");
+    break;
+  case GT:
+  case GTU:
+    fprintf (file, "H");
+    break;
+  case LT:
+  case LTU:
+    fprintf (file, "L");
+    break;
+  case GE:
+  case GEU:
+    fprintf (file, "NL");
+    break;
+  case LE:
+  case LEU:
+    fprintf (file, "NH");
+    break;
+  default:
+    debug_rtx (code);
+    fatal ("Unknown CC code\n");
+  }
+}
+
+static void
+output_inverse_branch_condition (FILE *file, rtx code)
+{
+  switch (GET_CODE (code)) {
+  case EQ:
+    fprintf (file, "NE ");
+    break;
+  case NE:
+    fprintf (file, "E");
+    break;
+  case GT:
+  case GTU:
+    fprintf (file, "NH");
+    break;
+  case LT:
+  case LTU:
+    fprintf (file, "NL");
+    break;
+  case GE:
+  case GEU:
+    fprintf (file, "L");
+    break;
+  case LE:
+  case LEU:
+    fprintf (file, "H");
+    break;
+  default:
+    debug_rtx (code);
+    fatal ("Unknown CC code\n");
+  }
+}
+
+static void
+do_print_operand_address (FILE *file, rtx addr, int off)
+{
+  rtx breg, xreg, plus, offset=0;
+
+  switch (GET_CODE (addr)) {
+  case REG:
+    fprintf (file, "%d(%s)", off, reg_names[REGNO (addr)]);
+    break;
+  case PLUS:
+    breg = 0;
+    xreg = 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;
+      }
+    /*
+     * %Nx in insn output
+     */
+
+    if (off) {
+      if (offset) {
+	offset = GEN_INT (INTVAL (offset) + off);
+      } else {
+	offset = GEN_INT (off);
+      }
+    }
+
+    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;
+  case LABEL_REF:
+    output_addr_const (file, addr);
+    fprintf (file,"-.LT_%X_%X(%d)", s390_function_count, s390_pool_count,
+	    BASE_REGISTER);
+    break;
+  case CONST:
+  case SYMBOL_REF:
+    output_addr_const (file, addr);
+    if (s390_pool_count == 0)
+      fprintf (file,"-.LT%X_%X(%d)",
+	      s390_function_count, s390_pool_count, BASE_REGISTER);
+    else
+      fprintf (file,"_%X-.LT%X_%X(%d)", s390_pool_count,
+	      s390_function_count, s390_pool_count, BASE_REGISTER);
+    
+    break;
+  default:
+    fprintf (file, "=eieieieieieie");
+      output_addr_const (file, addr);
+  }
+}
+
+
+
+
+void
+print_operand (FILE *file, rtx x,  char code)
+{
+  switch (GET_CODE (x))
+    {
+      static char curreg[4];
+    case REG:
+      {
+        if (code == 'N')
+          {
+            fprintf (file,"%s", reg_names[REGNO (x)+1]);
+            strcpy (curreg, reg_names[REGNO (x)+1]);
+          }
+        else if (code == 'O')
+          {
+            fprintf (file, "0");
+            curreg[0]='\0';
+          }
+        else
+          {
+            fprintf (file,"%s", reg_names[REGNO (x)]);
+            strcpy (curreg, reg_names[REGNO (x)]);
+          }
+        break;
+      }
+    case MEM:
+      {
+        rtx addr = XEXP (x, 0);
+        if (CONSTANT_P (addr)) {
+          if (code == 'N')
+            fprintf (file,"4+");
+          output_address (addr);
+        } else {
+          if (code == 'O') {
+            if (GET_CODE (addr) == PLUS) {
+              if (GET_CODE (XEXP (addr, 0)) == PLUS)
+                fprintf (file, "%d", INTVAL (XEXP (addr, 1)));
+              else if (GET_CODE (XEXP (addr, 1)) != REG)
+                fprintf (file, "%d", INTVAL (XEXP (addr, 1)));
+              else
+                fprintf (file, "0");}
+            else
+              fprintf (file, "0");
+          } else if (code == 'R') {
+            if (GET_CODE (addr) == PLUS) {
+              if (GET_CODE (XEXP (addr, 0)) == PLUS)
+                fprintf (file, "%s,%s",
+                         reg_names[REGNO (XEXP (XEXP (addr, 0), 0))],
+                         reg_names[REGNO (XEXP (XEXP (addr, 0), 1))]);
+              else  if (GET_CODE (XEXP (addr, 1)) != REG)
+                fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
+              else
+                fprintf (file, "%s,%s",
+                         reg_names[REGNO (XEXP (addr, 0))],
+                         reg_names[REGNO (XEXP (addr, 1))]);
+            }
+            else
+              fprintf (file, "%s", reg_names[REGNO (addr)]);
+          } else if (code == 'N') {
+	    do_print_operand_address (file, addr, 4);
+          }
+          else
+            output_address (addr);
+        }
+      }
+      break;
+    case PLUS:
+      do_print_operand_address (file, x, 0);
+      break;
+    case LABEL_REF:
+      if (code == 'Y')
+	fprintf (file, ".LT%X_%X-.", s390_function_count, s390_pool_count);
+      else {
+	output_addr_const (file, x);
+	fprintf (file,"-.LT%X_%X",
+		s390_function_count, s390_pool_count);
+      }
+      break;
+    case SYMBOL_REF:
+      if (code == 'g') {
+	assemble_name (file, XSTR (x, 0));
+        fprintf (file, "@GOT12(12)");
+      }
+      else if (code == 's') {
+	output_addr_const (file, x);
+      }
+      else
+        s390_output_const (file, x, SImode);
+      break;
+    case CONST_INT:
+      if (code == 'b')
+        fprintf (file, "%d", INTVAL (x) & 0xff);
+      else if (code == 'X')
+        fprintf (file, "%02X", INTVAL (x) & 0xff);
+      else if (code == 'h')
+        fprintf (file, "%d", (INTVAL (x) << 16) >> 16);
+      else if (code == 'p')
+        s390_output_const (file, x, SImode);
+      else
+        fprintf (file, "%d", INTVAL (x));
+      break;
+    case CONST_DOUBLE:
+      s390_output_const (file, x, DFmode);
+      break;
+    case CONST:
+      output_addr_const (file, x);
+      break;
+    default:
+      if (code == 'C')
+	output_branch_condition (file, x);
+      else if (code == 'D')
+	output_inverse_branch_condition (file, x);
+      else {
+	debug_rtx (x);
+	warning ("UNKNOWN in print_operand !?");
+	abort ();
+      }
+    }
+}
+
+void
+print_operand_address (file, addr)
+     FILE *file;
+     register rtx addr;
+{
+  do_print_operand_address (file, addr, 0);
+}
+
+void
+asm_generate_internal_label (char *label, char* prefix, int num)
+{
+   sprintf (label, "*@%s%d", prefix, num);
+}
+
+
+/* SYMBOL_REF_FLAGS marks global symbols. */
+void
+encode_section_info (tree decl)
+{
+  rtx sym_ref;
+  char *new_str;
+  /*
+   * section info stored at XSTR[-1]
+   * - F : global function
+   * - f : static function
+   */
+  if ((TREE_CODE (decl) == FUNCTION_DECL)  ||
+      (TREE_CODE (decl) == VAR_DECL)) {
+    sym_ref = XEXP (DECL_RTL (decl), 0);
+    new_str = permalloc (strlen (XSTR (sym_ref, 0))+3);
+    strcpy (new_str+2, XSTR (sym_ref, 0));
+    XSTR (sym_ref, 0) = new_str+2;
+    new_str[0] = ' ';
+    new_str[1] = '@';
+  }
+  if ((TREE_CODE (decl) == FUNCTION_DECL))
+    {
+       if (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
+       {
+         new_str[0] = 'F';
+         SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+       } else {
+         new_str[0] = 'f';
+       }
+    }
+  else if (TREE_CODE (decl) == VAR_DECL)
+    {
+      if (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
+        {
+          if (DECL_COMMON (decl) &&
+              (DECL_INITIAL (decl) == 0 ||
+               DECL_INITIAL (decl) == error_mark_node))
+            {
+              new_str[0] = 'U';
+            } else {
+              new_str[0] = 'I';
+            }
+          SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+        } else {                                   /* local (static) symbol*/
+          if (DECL_COMMON (decl) &&
+              (DECL_INITIAL (decl) == 0 ||
+               DECL_INITIAL (decl) == error_mark_node))
+            {
+              new_str[0] = 'u';
+            } else {
+              new_str[0] = 'i';
+            }
+        }
+    }
+}
+
+
+int
+s390_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost )
+{
+  rtx dep_rtx, insn_rtx;
+
+  dep_rtx = PATTERN (dep_insn);
+  insn_rtx = PATTERN (insn);
+
+  /* just an example
+  if ((GET_CODE (dep_rtx) == SET) &&
+      (GET_CODE (XEXP (dep_rtx, 0)) == REG)) {
+    dep_reg = REGNO (XEXP (dep_rtx, 0));
+
+    if ((GET_CODE (insn_rtx) == SET) &&
+        (GET_CODE (XEXP (insn_rtx, 0)) == REG ) &&
+        (GET_CODE (XEXP (insn_rtx, 1)) == PLUS) &&
+        (GET_CODE (XEXP (XEXP (insn_rtx, 1), 0)) == REG) &&
+        (REGNO (XEXP (XEXP (insn_rtx, 1), 0)) == dep_reg)) {
+      debug_rtx (dep_insn);
+      debug_rtx (insn);
+
+      fprintf (stderr, "cheap\n");
+      return cost;
+    }
+    }*/
+
+  return cost;
+}
+
+/* Pool concept for Linux 390:
+   - Function prologue saves used register 
+   - literal pool is dumped in prologue and  jump across with bras
+   - If function has more than 4 k literals, at about every 
+     S390_CHUNK_MAX offset in the function a literal pool will be
+     dumped
+     - in this case, a branch from one chunk to other chunk needs
+       a reload of base register at the code label branched to.  */
+
+
+
+rtx s390_pool_start_insn = NULL_RTX;
+
+/* Count of actual pool in function (-1 -> before function).  */
+
+int s390_pool_count = -1;
+
+
+static int pool_stop_uid;
+
+
+void 
+s390_asm_output_pool_prologue (FILE *file, char *fname, tree fndecl, int size)
+{
+  if (s390_pool_count>0) {
+    /*
+     * We are in an internal pool, branch over
+     */
+    fprintf (file,"\t.align 4\n\tBRAS\t13,0f\n.LT%X_%X:\t# Pool %d \n",
+	    s390_function_count, s390_pool_count, s390_pool_count);
+  }
+}
+
+/* Check if other addr is in different chunk than my addr,
+   return symbol_ref to other pool in that case.  */
+
+
+static int
+other_chunk (int *ltorg, int my_addr, int other_addr)
+{
+  int ad, i=0, j=0;
+
+  while ((ad = ltorg[i++])) {
+    if (INSN_ADDRESSES (ad) >= my_addr)
+      break;
+  }
+
+  while ((ad = ltorg[j++])) {
+    if (INSN_ADDRESSES (ad) > other_addr)
+      break;
+  }
+  
+  if (i==j)
+    return 0;
+
+  return 1;
+}
+
+/* Check, if other label is to far away to branch relative.  */
+
+static int 
+far_away (int my_addr, int other_addr)
+{
+  if (abs (my_addr - other_addr) > S390_REL_MAX)
+    return 1;
+  return 0;
+}
+
+
+
+static rtx 
+check_and_change_labels (rtx insn, int *ltorg_uids)
+{
+  rtx pattern, tmp, body, label1;
+  int addr0, addr1;
+
+  if (GET_CODE (insn) != JUMP_INSN) 
+    return insn;
+
+  pattern = PATTERN (insn);
+  
+
+  addr0 = INSN_ADDRESSES (INSN_UID (insn));
+  if (GET_CODE (pattern) == SET) {
+    body = XEXP (pattern, 1);
+    if (GET_CODE (body) == LABEL_REF) {
+      addr1 = INSN_ADDRESSES (INSN_UID (XEXP (body, 0)));
+
+      if (other_chunk (ltorg_uids, addr0, addr1)) {
+	SYMBOL_REF_USED (XEXP (body, 0)) = 1;
+      } 
+      if (far_away (addr0, addr1)) { 
+	emit_insn_before (gen_movsi (gen_rtx_REG (Pmode, RETURN_REGNUM),
+				   force_const_mem (Pmode, body)), insn);
+	tmp = emit_insn_before (gen_jump_long (
+	      gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, 14))), insn);
+	
+	remove_insn (insn);
+	return tmp;
+				   
+      }
+    } else if (GET_CODE (body) == IF_THEN_ELSE) {
+      if (GET_CODE (XEXP (body, 1)) == LABEL_REF) {
+	addr1 = INSN_ADDRESSES (INSN_UID (XEXP (XEXP (body, 1), 0)));
+
+	if (other_chunk (ltorg_uids, addr0, addr1)) {
+	  SYMBOL_REF_USED (XEXP (XEXP (body, 1), 0)) = 1;
+	} 
+
+	if (far_away (addr0, addr1)) {
+	  
+	  label1 = gen_label_rtx ();
+	  emit_jump_insn_before (gen_icjump (label1, XEXP (body, 0)), insn);
+	  emit_insn_before (gen_movsi (gen_rtx_REG (Pmode, RETURN_REGNUM),
+			   force_const_mem (Pmode, XEXP (body, 1))), insn);
+	  tmp = emit_jump_insn_before (gen_jump_long (
+		gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, 14))), insn);
+	  emit_label_before (label1, insn);
+	  remove_insn (insn);
+	  return tmp;
+	}
+      }
+    }
+
+  } else if (GET_CODE (pattern) == ADDR_VEC || 
+	     GET_CODE (pattern) == ADDR_DIFF_VEC) {
+    int i, diff_vec_p = GET_CODE (pattern) == ADDR_DIFF_VEC;
+    int len = XVECLEN (pattern, diff_vec_p);
+
+    for (i = 0; i < len; i++) {
+      addr1 = INSN_ADDRESSES (INSN_UID (XEXP (XVECEXP (pattern, diff_vec_p, i), 0)));
+      if (other_chunk (ltorg_uids, addr0, addr1)) {
+	SYMBOL_REF_USED (XEXP (XVECEXP (pattern, diff_vec_p, i), 0)) = 1;
+      } 
+    }
+  }
+  return insn;
+}
+
+static int chunk_max=0;
+
+void
+s390_final_chunkify (int chunkify)
+{
+  rtx insn, ninsn, tmp;
+  int addr, naddr, uids;
+
+  const char *asms;
+
+  int size = insn_current_address;
+
+  int *ltorg_uids;
+  int max_ltorg=0;
+
+  ltorg_uids = alloca (size/1024+1024);
+  memset (ltorg_uids, 0, size/1024+1024);
+
+  if (chunkify == 1) {
+    chunk_max = size * 2048 / get_pool_size ();
+    chunk_max = chunk_max > S390_CHUNK_MAX 
+      ? S390_CHUNK_MAX : chunk_max;
+  } 
+
+  for (insn=get_insns (); insn;insn = next_real_insn (insn)) {
+
+    if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      continue;
+
+    addr = INSN_ADDRESSES (INSN_UID (insn));
+    if ((ninsn = next_real_insn (insn))) {
+      naddr = INSN_ADDRESSES (INSN_UID (ninsn));
+    }
+    
+    if (chunkify && (addr/chunk_max != naddr/chunk_max)) {
+      for (tmp = insn; tmp;tmp = NEXT_INSN (tmp)) {
+	if (GET_CODE (tmp) == CODE_LABEL && 
+	    GET_CODE (NEXT_INSN (tmp)) != JUMP_INSN) {
+	  ltorg_uids[max_ltorg++] = INSN_UID (prev_real_insn (tmp));
+	  break;
+	} 
+	if (GET_CODE (tmp) == CALL_INSN) {
+	  ltorg_uids[max_ltorg++] = INSN_UID (tmp);
+	  break;
+	} 
+	if (INSN_ADDRESSES (INSN_UID (tmp)) - naddr > S390_CHUNK_OV) {
+	  debug_rtx (insn);
+	  debug_rtx (tmp);
+	  fatal ("s390 multiple literalpool support:"
+		 "\n No code label between this insn %X %X",
+		 naddr, INSN_ADDRESSES (INSN_UID (tmp)));
+	}
+      }
+      if (tmp == NULL) {
+	warning ("no code label found");
+      }
+    } else if (GET_CODE (PATTERN (insn)) == ASM_INPUT) {
+      asms = XSTR (PATTERN (insn), 0);
+
+      if ((memcmp (asms,".section", 8) == 0) ||
+	  (memcmp (asms,".text", 5) == 0)    ||
+	  (memcmp (asms,"\t.section", 9) == 0) ||
+	  (memcmp (asms,"\t.text", 6) == 0))  {
+	ltorg_uids[max_ltorg++] = INSN_UID (insn);
+	emit_insn_before (gen_rtx_ASM_INPUT (VOIDmode,
+					   ".align 4"), insn);
+      }
+    }
+  }
+  ltorg_uids[max_ltorg] = 0;
+  for (insn=get_insns (), uids=0; insn;insn = next_real_insn (insn)) {
+    if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      continue;
+    if (INSN_UID (insn) == ltorg_uids[uids]) {
+      emit_insn_after (gen_ltorg (
+		       GEN_INT (ltorg_uids[++uids])),
+		       insn);
+    } 
+    if (GET_CODE (insn) == JUMP_INSN) {
+      insn = check_and_change_labels (insn, ltorg_uids);
+    }
+  }
+  if (chunkify) {
+    for (insn=get_insns (); insn; insn = next_insn (insn)) {
+      if (GET_CODE (insn) == CODE_LABEL) {
+	if (SYMBOL_REF_USED (insn)) {
+	  emit_insn_after (gen_reload_base (
+					  gen_rtx_LABEL_REF (Pmode, XEXP (insn, 0))), insn);
+	}
+      }
+    }
+  }
+
+  pool_stop_uid = ltorg_uids[0];
+
+}
+
+/* Return 1 if next literal pool is reached (check for ltorg insn)
+   maybe should use unspec insn.  */
+
+
+int 
+s390_stop_dump_lit_p (rtx insn)
+{
+  rtx body=PATTERN (insn);
+  if (GET_CODE (body) == PARALLEL
+      && GET_CODE (XVECEXP (body, 0, 0)) == SET
+      && GET_CODE (XVECEXP (body, 0, 1)) == USE
+      && GET_CODE (XEXP ((XVECEXP (body, 0, 1)), 0)) == CONST_INT
+      && GET_CODE (SET_DEST (XVECEXP (body, 0, 0))) == REG
+      && REGNO (SET_DEST (XVECEXP (body, 0, 0))) == BASE_REGISTER
+      && SET_SRC (XVECEXP (body, 0, 0)) == pc_rtx) {
+    return 1;
+  }
+  else
+    return 0;   
+}
+
+void
+s390_dump_literal_pool (rtx act_insn, rtx stop)
+{
+  s390_pool_start_insn = act_insn;
+  pool_stop_uid = INTVAL (stop);
+  s390_pool_count++;
+  output_constant_pool (current_function_name, current_function_decl);
+}
+
diff -u -r --new-file egcs-20001002/gcc/config/s390/s390.h egcs-20001002-s390/gcc/config/s390/s390.h
--- egcs-20001002/gcc/config/s390/s390.h	Thu Jan  1 01:00:00 1970
+++ egcs-20001002-s390/gcc/config/s390/s390.h	Fri Oct 13 15:07:33 2000
@@ -0,0 +1,1621 @@
+/* Definitions of target machine for GNU compiler, for IBM S/390
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Hartmut Penner (hpenner@de.ibm.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.  */
+
+#ifndef _S390_H
+#define _S390_H
+
+#define TARGET_VERSION fprintf (stderr, " (S/390)");
+
+/* Run-time compilation parameters selecting different hardware subsets.  */
+
+extern int target_flags;
+
+/* The current function count for create unique internal labels.  */
+
+extern int s390_function_count;
+
+/* The amount of space used for outgoing arguments.  */
+
+extern int current_function_outgoing_args_size;
+
+/* Target machine storage layout.  */
+
+/* Define this if most significant bit is lowest numbered in instructions
+   that operate on numbered bit-fields.  */
+
+#define BITS_BIG_ENDIAN 1
+
+/* Define this if most significant byte of a word is the lowest numbered.  */
+
+#define BYTES_BIG_ENDIAN 1
+
+/* Define this if MS word of a multiword is the lowest numbered.  */
+
+#define WORDS_BIG_ENDIAN 1
+
+/* Number of bits in an addressable storage unit.  */
+
+#define BITS_PER_UNIT 8
+
+/* Width in bits of a "word", which is the contents of a machine register.  */
+
+#define BITS_PER_WORD 32
+
+/* Width of a word, in units (bytes).  */
+
+#define UNITS_PER_WORD 4
+
+/* Width in bits of a pointer.  See also the macro `Pmode' defined below.  */
+
+#define POINTER_SIZE 32
+
+/* Define this macro if it is advisable to hold scalars in registers
+   in a wider mode than that declared by the program.  In such cases,
+   the value is constrained to be within the bounds of the declared
+   type, but kept valid in the wider mode.  The signedness of the
+   extension may differ from that of the type.  */
+
+/*#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+  if (GET_MODE_CLASS (MODE) == MODE_INT                 \
+      && GET_MODE_SIZE (MODE) < UNITS_PER_WORD)         \
+   (MODE) = SImode;
+*/
+
+/* Defining PROMOTE_FUNCTION_ARGS eliminates some unnecessary zero/sign
+   extensions applied to char/short functions arguments.  Defining
+   PROMOTE_FUNCTION_RETURN does the same for function returns.  */
+
+#define PROMOTE_FUNCTION_ARGS
+#define PROMOTE_FUNCTION_RETURN
+
+/* Allocation boundary (in *bits*) for storing pointers in memory.  */
+
+#define POINTER_BOUNDARY 32
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list.  */
+
+#define PARM_BOUNDARY 32
+
+/* Boundary (in *bits*) on which stack pointer should be aligned.  */
+
+#define STACK_BOUNDARY 64
+
+/* Allocation boundary (in *bits*) for the code of a function.  */
+
+#define FUNCTION_BOUNDARY 32
+
+/* There is no point aligning anything to a rounder boundary than this.  */
+
+#define BIGGEST_ALIGNMENT 64
+
+/* Alignment of field after `int : 0' in a structure.  */
+
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* Define this if move instructions will actually fail to work when given
+   unaligned data.  */
+
+#define STRICT_ALIGNMENT 0
+
+/* real arithmetic */
+
+#define REAL_ARITHMETIC
+
+/* Define target floating point format.  */
+
+#undef TARGET_FLOAT_FORMAT
+#ifdef IEEE_FLOAT
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+#else
+#define TARGET_FLOAT_FORMAT IBM_FLOAT_FORMAT
+#endif
+
+/* Define if special allocation order desired.  */
+
+#ifndef IEEE_FLOAT
+#define REG_ALLOC_ORDER \
+{  1, 2, 3, 4, 5, 0, 11, 10, 9, 8, 7, 6, 16, 17, 18, 19, 13, 14, 15, 12  }
+#else
+#define REG_ALLOC_ORDER                                         \
+{  1, 2, 3, 4, 5, 0, 11, 10, 9, 8, 7, 6,                        \
+   16, 17, 18, 19, 20, 21, 22, 23,                              \
+   24, 25, 26, 27, 28, 29, 30, 31,                              \
+   13, 14, 15, 12, 32  }
+#endif
+
+/* Standard register usage.  */
+
+/* Number of actual hardware registers.  The hardware registers are
+   assigned numbers for the compiler from 0 to just below
+   FIRST_PSEUDO_REGISTER.
+   All registers that the compiler knows about must be given numbers,
+   even those that are not normally considered general registers.
+   For the 390, we give the data registers numbers 0-15,
+   and the floating point registers numbers 16-19.
+   G5 and following have 16 IEEE floating point register,
+   which get numbers 16-31.  */
+
+#ifndef IEEE_FLOAT
+#define FIRST_PSEUDO_REGISTER 20
+#else
+#define FIRST_PSEUDO_REGISTER 33
+#endif
+
+/* The following register have a fix usage
+   GPR 12: GOT register points to the GOT, setup in prologue,
+           GOT contains pointer to variables in shared libraries 
+   GPR 13: Base register setup in prologue to point to the
+           literal table of each function
+   GPR 14: Return registers holds the return address
+   GPR 15: Stack pointer */
+
+#define PIC_OFFSET_TABLE_REGNUM 12
+#define BASE_REGISTER 13
+#define RETURN_REGNUM 14
+#define STACK_POINTER_REGNUM 15
+
+#define FIXED_REGISTERS				\
+{ 0, 0, 0, 0, 					\
+  0, 0, 0, 0, 					\
+  0, 0, 0, 0, 					\
+  1, 1, 1, 1,					\
+  0, 0, 0, 0, 					\
+  0, 0, 0, 0, 					\
+  0, 0, 0, 0, 					\
+  0, 0, 0, 0, 					\
+  1 }
+
+
+/* 1 for registers not available across function calls.  These must include
+   the FIXED_REGISTERS and also any registers that can be used without being
+   saved.
+   The latter must include the registers where values are returned
+   and the register where structure-value addresses are passed.  */
+
+#ifndef IEEE_FLOAT
+#define CALL_USED_REGISTERS                                             \
+{ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0 }
+/*0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19*/
+#else
+#define CALL_USED_REGISTERS                                             \
+{ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,                       \
+  1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+#endif
+
+/* The following register have a special usage
+   GPR 11: Frame pointer if needed to point to automatic variables. 
+   GPR 32: In functions with more the 5 args this register
+           points to that arguments, it is always eliminated
+	   with stack- or frame-pointer.  */
+
+#define FRAME_POINTER_REGNUM 11
+
+#define ARG_POINTER_REGNUM 32
+
+/* We use the register %r0 to pass the static chain to a nested function.
+  
+   Note: It is assumed that this register is call-clobbered!
+         We can't use any of the function-argument registers either,
+         and register 1 is needed by the trampoline code, so we have
+         no other choice but using this one ...  */
+
+#define STATIC_CHAIN_REGNUM 0
+
+/* 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.  */
+
+#define HARD_REGNO_NREGS(REGNO, MODE)                           \
+  ((REGNO) > 15 ?                                               \
+   ((GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) ? 2 : 1) :    \
+    (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.
+   The gprs can hold QI, HI, SI, SF, DF, SC and DC.
+   Even gprs can hold DI.
+   The floating point registers can hold DF, SF, DC and SC.  */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE)                 \
+  ((REGNO) > 15 ?                                       \
+   (GET_MODE_CLASS (MODE) == MODE_FLOAT ||              \
+    (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)) :    \
+   ((MODE) != DImode || ((REGNO) & 1) == 0 ))
+
+
+/* Value is 1 if it is a good idea to tie two pseudo registers when one has
+   mode MODE1 and one has mode MODE2.
+   If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+   for any hard reg, then this must be 0 for correct output.  */
+
+#define MODES_TIEABLE_P(MODE1, MODE2)		\
+   (((MODE1) == SFmode || (MODE1) == DFmode)	\
+   == ((MODE2) == SFmode || (MODE2) == DFmode))
+
+/* Mark external references. There is no respect to init or not.
+   See note on ASM_OUTPUT_EXTERNAL */
+
+#define ENCODE_SECTION_INFO(decl) encode_section_info (decl)
+
+
+/* This is an array of structures.  Each structure initializes one pair
+   of eliminable registers.  The "from" register number is given first,
+   followed by "to".  Eliminations of the same "from" register are listed
+   in order of preference.  */
+
+#define ELIMINABLE_REGS				\
+{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},	\
+ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},	\
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}}  
+
+#define CAN_ELIMINATE(FROM, TO) (1)
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) 			  \
+{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) 	  \
+  { (OFFSET) = 0; }     						  \
+  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)  \
+  { (OFFSET) = s390_arg_frame_offset (); }     				  \
+  else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)  \
+  { (OFFSET) = s390_arg_frame_offset (); }     				  \
+}
+
+#define CAN_DEBUG_WITHOUT_FP
+
+/* Value should be nonzero if functions must have frame pointers.
+   Zero means the frame pointer need not be set up (and parms may be
+   accessed via the stack pointer) in functions that seem suitable.
+   This is computed in `reload', in reload1.c.  */
+
+
+/* FIXME !!! Currently (08/2000) reload does not work right regarding 
+   frame pointer elimination. It's only done partially, and 
+   frame_pointer_needed is set to zero.  */
+#define FRAME_POINTER_REQUIRED 1
+
+
+/* Define the classes of registers for register constraints in the
+   machine description.  Also define ranges of constants.
+  
+   One of the classes must always be named ALL_REGS and include all hard regs.
+   If there is more than one class, another class must be named NO_REGS
+   and contain no registers.
+ 
+   The name GENERAL_REGS must be the name of a class (or an alias for
+   another name such as ALL_REGS).  This is the class of registers
+   that is allowed by "g" or "r" in a register constraint.
+   Also, registers outside this class are allocated only when
+   instructions express preferences for them.
+  
+   The classes must be numbered in nondecreasing order; that is,
+   a larger-numbered class must never be contained completely
+   in a smaller-numbered class.
+  
+   For any two classes, it is very desirable that there be another
+   class that represents their union.  */
+
+/*#define SMALL_REGISTER_CLASSES 1*/
+
+enum reg_class
+{
+  NO_REGS, ADDR_REGS, GENERAL_REGS,
+  FP_REGS, ALL_REGS, LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file.  */
+
+#define REG_CLASS_NAMES                                                 \
+{ "NO_REGS","ADDR_REGS", "GENERAL_REGS", "FP_REGS", "ALL_REGS" }
+
+/* Define which registers fit in which classes.  This is an initializer for
+   a vector of HARD_REG_SET of length N_REG_CLASSES.
+   G5 and latter have 16 register and support IEEE floating point operations.  */
+
+#ifndef IEEE_FLOAT
+#define REG_CLASS_CONTENTS {0, 0x0fffe, 0x0ffff, 0xf0000, 0xfffff}
+#else
+#define REG_CLASS_CONTENTS \
+{				       			\
+  { 0x00000000, 0x00000000 },	/* NO_REGS */		\
+  { 0x0000fffe, 0x00000001 },	/* ADDR_REGS */		\
+  { 0x0000ffff, 0x00000001 },	/* GENERAL_REGS */	\
+  { 0xffff0000, 0x00000000 },	/* FP_REGS */		\
+  { 0xffffffff, 0x00000001 },	/* ALL_REGS */		\
+}
+#endif
+
+
+/* The same information, inverted:
+   Return the class number of the smallest class containing
+   reg number REGNO.  This could be a conditional expression
+   or could index an array.  */
+
+#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
+
+extern enum reg_class regclass_map[];	/* smalled class containing REGNO   */
+
+/* The class value for index registers, and the one for base regs.  */
+
+#define INDEX_REG_CLASS ADDR_REGS
+#define BASE_REG_CLASS ADDR_REGS
+
+/* Get reg_class from a letter such as appears in the machine description.  */
+
+#define REG_CLASS_FROM_LETTER(C)                                        \
+  ((C) == 'a' ? ADDR_REGS :                                             \
+   (C) == 'd' ? GENERAL_REGS :                                          \
+   (C) == 'f' ? FP_REGS : NO_REGS)
+
+/* The letters I, J, K, L and M in a register constraint string can be used
+   to stand for particular ranges of immediate operands.
+   This macro defines what the ranges are.
+   C is the letter, and VALUE is a constant value.
+   Return 1 if VALUE is in the range specified by C.  */
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C)                                 \
+  ((C) == 'I' ? (unsigned long) (VALUE) < 256 :                         \
+   (C) == 'J' ? (unsigned long) (VALUE) < 4096 :                        \
+   (C) == 'K' ? (VALUE) >= -32768 && (VALUE) < 32768 : 0)
+
+/* Similar, but for floating constants, and defining letters G and H.
+   Here VALUE is the CONST_DOUBLE rtx itself.  */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)  1
+
+/* 'Q' means a memory-reference for a S-type operand.  */
+#define EXTRA_CONSTRAINT(OP, C)                                          \
+     ((C) == 'Q' ?  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.  */
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS)                                 \
+    (GET_CODE (X) == CONST_DOUBLE ?                                      \
+     (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? FP_REGS : ADDR_REGS) :\
+     (GET_CODE (X) == CONST_INT ?                                        \
+     (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? FP_REGS : ADDR_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.  */
+
+#define CLASS_MAX_NREGS(CLASS, MODE)   					\
+     ((CLASS) == FP_REGS ? 						\
+      (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) :  		\
+      (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* If we are copying between FP registers and anything else, we need a memory
+   location.  */
+
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+ ((CLASS1) != (CLASS2) && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS))
+
+/* A C expression whose value is nonzero if pseudos that have been
+   assigned to registers of class CLASS would likely be spilled
+   because registers of CLASS are needed for spill registers.
+
+   The default value of this macro returns 1 if CLASS has exactly one
+   register and zero otherwise.  On most machines, this default
+   should be used.  Only define this macro to some other expression
+   if pseudo allocated by `local-alloc.c' end up in memory because
+   their hard registers were needed for spill registers.  If this
+   macro returns nonzero for those classes, those pseudos will only
+   be allocated by `global.c', which knows how to reallocate the
+   pseudo to another register.  If there would not be another
+   register available for reallocation, you should not change the
+   definition of this macro since the only effect of such a
+   definition would be to slow down register allocation.  */
+
+/* Stack layout; function entry, exit and calling.  */
+
+/* The current return address is on Offset 56 of the current frame
+   if we are in an leaf_function. Otherwise we have to go one stack
+   back.
+   The return address of anything farther back is accessed normally
+   at an offset of 56 from the frame pointer.
+
+   FIXME: builtin_return_addr does not work correctly in a leaf
+          function, we need to find way to find out, if we
+          are in a leaf function
+  */
+
+#define _RETURN_ADDR_OFFSET 56
+
+#define RETURN_ADDR_RTX(count, frame)                                   \
+   gen_rtx_MEM (Pmode,                                                  \
+            memory_address (Pmode,                                      \
+                              plus_constant (                           \
+                              copy_to_reg (gen_rtx_MEM (Pmode,          \
+                              memory_address (Pmode, frame))),          \
+                              _RETURN_ADDR_OFFSET)));
+
+/* The following macros will turn on dwarf2 exception hndling
+   Other code location for this exception handling are 
+   in s390.md (eh_return insn) and in linux.c in the prologue.  */
+
+#define INCOMING_RETURN_ADDR_RTX  gen_rtx_REG (Pmode, RETURN_REGNUM)
+
+/* We have 31 bit mode.  */
+
+#define MASK_RETURN_ADDR (GEN_INT (0x7fffffff))
+
+/* Location, from where return address to load.  */
+
+#define DWARF_FRAME_RETURN_COLUMN  14
+
+/* Define this if pushing a word on the stack makes the stack pointer a
+   smaller address.  */
+
+#define STACK_GROWS_DOWNWARD
+
+/* Define this if the nominal address of the stack frame is at the
+   high-address end of the local variables; that is, each additional local
+   variable allocated goes at a more negative offset in the frame.  */
+
+/* #define FRAME_GROWS_DOWNWARD   */
+
+/* Offset from stack-pointer to first location of outgoing args.  */
+
+#define STACK_POINTER_OFFSET 96
+
+/* Offset within stack frame to start allocating local variables at.
+   If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
+   first local allocated.  Otherwise, it is the offset to the BEGINNING
+   of the first local allocated.  */
+
+#define STARTING_FRAME_OFFSET \
+     (STACK_POINTER_OFFSET + current_function_outgoing_args_size)
+
+#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0
+
+/* If we generate an insn to push BYTES bytes, this says how many the stack
+   pointer really advances by.  On S/390, we have no push instruction.  */
+
+/* #define PUSH_ROUNDING(BYTES) */
+
+/* Accumulate the outgoing argument count so we can request the right
+   DSA size and determine stack offset.  */
+
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* Offset from the stack pointer register to an item dynamically
+   allocated on the stack, e.g., by `alloca'.
+
+   The default value for this macro is `STACK_POINTER_OFFSET' plus the
+   length of the outgoing arguments.  The default is correct for most
+   machines.  See `function.c' for details.  */
+#define STACK_DYNAMIC_OFFSET(FUNDECL) (STARTING_FRAME_OFFSET)
+
+/* Offset of first parameter from the argument pointer register value. 
+   On the S/390, we define the argument pointer to the start of the fixed
+   area.  */
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+/* Define this if stack space is still allocated for a parameter passed
+   in a register.  The value is the number of bytes allocated to this
+   area.  */
+/* #define REG_PARM_STACK_SPACE(FNDECL)    32 */
+
+/* Define this if the above stack space is to be considered part of the
+   space allocated by the caller.  */
+/* #define OUTGOING_REG_PARM_STACK_SPACE */
+
+/* 1 if N is a possible register number for function argument passing.
+   On S390, general registers 2 - 6 and floating point register 0 and 2
+   are used in this way.  */
+
+#define FUNCTION_ARG_REGNO_P(N) (((N) >=2 && (N) <7) || \
+                                 (N) == 16 || (N) == 17)
+
+/* Define a data type for recording info about an argument list during
+   the scan of that argument list.  This data type should hold all
+   necessary information about the function itself and about the args
+   processed so far, enough to enable macros such as FUNCTION_ARG to
+   determine where the next arg should go.  */
+
+typedef struct s390_arg_structure
+{
+  int gprs;			/* gpr so far */
+  int fprs;			/* fpr so far */
+}
+CUMULATIVE_ARGS;
+
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to
+   a function whose data type is FNTYPE.
+   For a library call, FNTYPE is 0.  */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, NN) \
+  ((CUM).gprs=0, (CUM).fprs=0)
+
+/* Update the data in CUM to advance over an argument of mode MODE and
+   data type TYPE.  (TYPE is null for libcalls where that information
+   may not be available.) */
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)                    \
+  s390_function_arg_advance(&CUM, MODE, TYPE, NAMED)
+
+/* Define where to put the arguments to a function.  Value is zero to push
+   the argument on the stack, or a hard register in which to store the
+   argument.  */
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)   \
+  s390_function_arg(&CUM, MODE, TYPE, NAMED)
+
+/* Define where to expect the arguments of a function.  Value is zero, if
+   the argument is on the stack, or a hard register in which the argument
+   is stored. It is the same like FUNCTION_ARG, except for unnamed args
+   That means, that all in case of varargs used, the arguments are expected
+   from the stack. 
+   S/390 has already space on the stack for args coming in registers, 
+   they are pushed in prologue, if needed.  */  
+
+
+/* Define the `__builtin_va_list' type.  */
+
+#define BUILD_VA_LIST_TYPE(VALIST) \
+  (VALIST) = s390_build_va_list ()
+
+/* Implement `va_start' for varargs and stdarg.  */
+
+#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
+  s390_va_start (stdarg, valist, nextarg)
+
+/* Implement `va_arg'.  */
+
+#define EXPAND_BUILTIN_VA_ARG(valist, type) \
+  s390_va_arg (valist, type)
+
+/* For an arg passed partly in registers and partly in memory, this is the
+   number of registers used.  For args passed entirely in registers or
+   entirely in memory, zero.  */
+
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
+
+
+/* Define if returning from a function call automatically pops the
+   arguments described by the number-of-args field in the call.  */
+
+#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).
+   If the precise function being called is known, FUNC is its FUNCTION_DECL;
+   otherwise, FUNC is 15.  */
+
+#define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT       \
+                       || TARGET_SOFT_FLOAT ) ? 2 : 16)
+
+
+/* for structs the address is passed, and the Callee makes a
+   copy, only if needed */
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
+  s390_function_arg_pass_by_reference (MODE, TYPE)
+
+
+/* Register 2 (and 3) for integral values
+   or floating point register 0 (and 2) for fp values are used.  */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC)                                   \
+  gen_rtx_REG (TYPE_MODE (VALTYPE), RET_REG (TYPE_MODE (VALTYPE)))
+
+/* Define how to find the value returned by a library function assuming
+   the value has mode MODE.  */
+
+#define LIBCALL_VALUE(MODE)  gen_rtx_REG (MODE, RET_REG (MODE))
+
+/* 1 if N is a possible register number for a function value.  */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
+
+/* The definition of this macro implies that there are cases where
+   a scalar value cannot be returned in registers.  */
+
+#define RETURN_IN_MEMORY(type)                                  \
+  (TYPE_MODE (type) == BLKmode || TYPE_MODE (type) == DCmode)
+
+/* Mode of stack savearea.
+   FUNCTION is VOIDmode because calling convention maintains SP.
+   BLOCK needs Pmode for SP.
+   NONLOCAL needs twice Pmode to maintain both backchain and SP.  */
+
+#define STACK_SAVEAREA_MODE(LEVEL)      \
+  (LEVEL == SAVE_FUNCTION ? VOIDmode    \
+  : LEVEL == SAVE_NONLOCAL ? DImode : Pmode)
+
+/* Structure value address is passed as invisible first argument (gpr 2).  */
+
+#define STRUCT_VALUE 0
+
+/* This macro definition sets up a default value for `main' to return.  */
+
+#define DEFAULT_MAIN_RETURN  c_expand_return (integer_zero_node)
+
+/* Length in units of the trampoline for entering a nested function.  */
+
+#define TRAMPOLINE_SIZE 20
+
+/* Initialize the dynamic part of trampoline.  */
+
+#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT)                       \
+   s390_initialize_trampoline ((ADDR), (FNADDR), (CXT))
+
+/* Template for constant part of trampoline.  */
+
+#define TRAMPOLINE_TEMPLATE(FILE)                                       \
+   s390_trampoline_template (FILE)
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+   for profiling a function entry.  */
+
+#define FUNCTION_PROFILER(FILE, LABELNO)  				  \
+do {                                                                      \
+    extern rtx s390_profile[];  					  \
+    extern s390_pool_count;     					  \
+    rtx tmp;                                                              \
+    static char label[128];                                               \
+    fprintf (FILE, "# function profiler \n");                             \
+    s390_pool_count = 0;                                                  \
+    output_asm_insn ("st    14,4(15)", s390_profile);     		  \
+    output_asm_insn ("l     14,%4", s390_profile);		       	  \
+    output_asm_insn ("l     1,%9", s390_profile);		          \
+    if (flag_pic) {                                                       \
+      output_asm_insn ("ar    1,13", s390_profile);                       \
+      output_asm_insn ("bas   14,0(14,13)", s390_profile);                \
+    } else {							          \
+      output_asm_insn ("basr  14,14", s390_profile);	                  \
+    }                                                                     \
+    s390_pool_count = 0;                                                  \
+    output_asm_insn ("l     14,4(15)", s390_profile);                     \
+} while (0)
+
+/* #define PROFILE_BEFORE_PROLOGUE */
+
+/* There are three profiling modes for basic blocks available.
+   The modes are selected at compile time by using the options
+   -a or -ax of the gnu compiler.
+   The variable `profile_block_flag' will be set according to the
+   selected option.
+
+   profile_block_flag == 0, no option used:
+
+      No profiling done.
+
+   profile_block_flag == 1, -a option used.
+
+      Count frequency of execution of every basic block.
+
+   profile_block_flag == 2, -ax option used.
+
+      Generate code to allow several different profiling modes at run time. 
+      Available modes are:
+             Produce a trace of all basic blocks.
+             Count frequency of jump instructions executed.
+      In every mode it is possible to start profiling upon entering
+      certain functions and to disable profiling of some other functions.
+
+    The result of basic-block profiling will be written to a file `bb.out'.
+    If the -ax option is used parameters for the profiling will be read
+    from file `bb.in'.
+
+*/
+
+/* The following macro shall output assembler code to FILE
+   to initialize basic-block profiling.
+
+   If profile_block_flag == 2
+
+	Output code to call the subroutine `__bb_init_trace_func'
+	and pass two parameters to it. The first parameter is
+	the address of a block allocated in the object module.
+	The second parameter is the number of the first basic block
+	of the function.
+
+	The name of the block is a local symbol made with this statement:
+	
+	    ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+	Of course, since you are writing the definition of
+	`ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+	can take a short cut in the definition of this macro and use the
+	name that you know will result.
+
+	The number of the first basic block of the function is
+	passed to the macro in BLOCK_OR_LABEL.
+
+	If described in a virtual assembler language the code to be
+	output looks like:
+
+		parameter1 <- LPBX0
+		parameter2 <- BLOCK_OR_LABEL
+		call __bb_init_trace_func
+
+    else if profile_block_flag != 0
+
+	Output code to call the subroutine `__bb_init_func'
+	and pass one single parameter to it, which is the same
+	as the first parameter to `__bb_init_trace_func'.
+
+	The first word of this parameter is a flag which will be nonzero if
+	the object module has already been initialized.  So test this word
+	first, and do not call `__bb_init_func' if the flag is nonzero.
+	Note: When profile_block_flag == 2 the test need not be done
+	but `__bb_init_trace_func' *must* be called.
+
+	BLOCK_OR_LABEL may be used to generate a label number as a
+	branch destination in case `__bb_init_func' will not be called.
+
+	If described in a virtual assembler language the code to be
+	output looks like:
+
+		cmp (LPBX0),0
+		jne local_label
+		parameter1 <- LPBX0
+		call __bb_init_func
+local_label:
+
+*/
+
+#undef	FUNCTION_BLOCK_PROFILER
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL)			    \
+do									    \
+  {									    \
+    extern rtx s390_profile[];						    \
+    fprintf (FILE, "# function block profiler %d \n", profile_block_flag);  \
+    output_asm_insn ("ipm   0", s390_profile);     		    	    \
+    output_asm_insn ("ahi   15,-128", s390_profile);                  	    \
+    output_asm_insn ("stm   14,5,96(15)", s390_profile);     		    \
+    output_asm_insn ("l     2,%6", s390_profile);     		    	    \
+    if (flag_pic)							    \
+      output_asm_insn ("ar    2,13", s390_profile);			    \
+    switch (profile_block_flag) 					    \
+      {									    \
+      case 2:								    \
+        output_asm_insn ("l     4,%1", s390_profile);		       	    \
+        if (BLOCK_OR_LABEL < 0x8000) {                                      \
+	  s390_profile[8] = GEN_INT (BLOCK_OR_LABEL);                       \
+          output_asm_insn ("lhi   3,%8", s390_profile);                     \
+        } else {                                         	     	    \
+          int bo = BLOCK_OR_LABEL;                                          \
+	  s390_profile[8] = GEN_INT ((bo&0xffff8000)>>15);                  \
+          output_asm_insn ("lhi   3,%8", s390_profile);                     \
+          output_asm_insn ("sll   3,15", s390_profile);                     \
+	  s390_profile[8] = GEN_INT (bo&0x7fff);                            \
+          output_asm_insn ("ahi   3,%8", s390_profile);                     \
+        }                                                                   \
+	break;								    \
+      default:								    \
+        output_asm_insn ("l     4,%0", s390_profile);	      		    \
+	output_asm_insn ("cli   3(2),0", s390_profile);              	    \
+	output_asm_insn ("jne   2f", s390_profile);			    \
+	break;								    \
+      }									    \
+    if (flag_pic)							    \
+      output_asm_insn ("bas   14,0(4,13)", s390_profile);	       	    \
+    else								    \
+      output_asm_insn ("basr  14,4", s390_profile);	                    \
+    output_asm_insn ("2:", s390_profile);                                   \
+    output_asm_insn ("lm    14,5,96(15)", s390_profile);                    \
+    output_asm_insn ("ahi   15,128", s390_profile);		            \
+    output_asm_insn ("spm   0", s390_profile);				    \
+} while (0)
+
+/* The following macro shall output assembler code to FILE
+   to increment a counter associated with basic block number BLOCKNO.
+
+   If profile_block_flag == 2
+
+	Output code to initialize the global structure `__bb' and
+	call the function `__bb_trace_func' which will increment the
+	counter.
+
+	`__bb' consists of two words. In the first word the number
+	of the basic block has to be stored. In the second word
+	the address of a block allocated in the object module 
+	has to be stored.
+
+	The basic block number is given by BLOCKNO.
+
+	The address of the block is given by the label created with 
+
+	    ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+	by FUNCTION_BLOCK_PROFILER.
+
+	Of course, since you are writing the definition of
+	`ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+	can take a short cut in the definition of this macro and use the
+	name that you know will result.
+
+	If described in a virtual assembler language the code to be
+	output looks like:
+
+		move BLOCKNO -> (__bb)
+		move LPBX0 -> (__bb+4)
+		call __bb_trace_func
+
+	Note that function `__bb_trace_func' must not change the
+	machine state, especially the flag register. To grant
+	this, you must output code to save and restore registers
+	either in this macro or in the macros MACHINE_STATE_SAVE
+	and MACHINE_STATE_RESTORE. The last two macros will be
+	used in the function `__bb_trace_func', so you must make
+	sure that the function prologue does not change any 
+	register prior to saving it with MACHINE_STATE_SAVE.
+
+   else if profile_block_flag != 0
+
+	Output code to increment the counter directly.
+	Basic blocks are numbered separately from zero within each
+	compiled object module. The count associated with block number
+	BLOCKNO is at index BLOCKNO in an array of words; the name of 
+	this array is a local symbol made with this statement:
+
+	    ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+
+	Of course, since you are writing the definition of
+	`ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+	can take a short cut in the definition of this macro and use the
+	name that you know will result. 
+
+	If described in a virtual assembler language the code to be
+	output looks like:
+
+		inc (LPBX2+4*BLOCKNO)
+
+*/
+
+#define BLOCK_PROFILER(FILE, BLOCKNO)		                	   \
+do									   \
+  {									   \
+    extern rtx s390_profile[];						   \
+    fprintf (FILE, "# block profiler %d block %d \n",                      \
+	             profile_block_flag,BLOCKNO); 	                   \
+    output_asm_insn ("ipm   14", s390_profile);     		    	   \
+    output_asm_insn ("ahi   15,-128", s390_profile);     	       	   \
+    output_asm_insn ("stm   14,5,96(15)", s390_profile);     		   \
+    switch (profile_block_flag) 					   \
+      {									   \
+      case 2:								   \
+        output_asm_insn ("l     4,%2", s390_profile);     	     	   \
+        output_asm_insn ("l     2,%5", s390_profile);     	     	   \
+        if (flag_pic)							   \
+          output_asm_insn ("ar    2,13", s390_profile);			   \
+        if (BLOCKNO < 0x8000) {                                            \
+	  s390_profile[7] = GEN_INT ((BLOCKNO)*4);                         \
+          output_asm_insn ("lhi   3,%8", s390_profile);                    \
+        } else {                                         	     	   \
+          int bo = BLOCKNO;                                                \
+	  s390_profile[8] = GEN_INT ((bo&0xffff8000)>>15);                 \
+          output_asm_insn ("lhi   3,%8", s390_profile);                    \
+          output_asm_insn ("sll   3,15", s390_profile);                    \
+	  s390_profile[8] = GEN_INT (bo&0x7fff);                           \
+          output_asm_insn ("ahi   3,%7", s390_profile);                    \
+        }                                                                  \
+        output_asm_insn ("st    3,0(2)", s390_profile);     	     	   \
+        output_asm_insn ("mvc   0(4,2),%5", s390_profile);     	     	   \
+        if (flag_pic)							   \
+          output_asm_insn ("bas   14,0(4,13)", s390_profile);		   \
+        else								   \
+          output_asm_insn ("basr  14,4", s390_profile);	                   \
+	break;								   \
+      default:								   \
+        if (BLOCKNO < 0x2000) {                                            \
+	  s390_profile[8] = GEN_INT ((BLOCKNO)*4);                         \
+          output_asm_insn ("lhi   2,%8", s390_profile);                    \
+        } else {                                         	     	   \
+          int bo = BLOCKNO*4;                                              \
+	  s390_profile[8] = GEN_INT ((bo&0xffff8000)>>15);                 \
+          output_asm_insn ("lhi   2,%8", s390_profile);                    \
+          output_asm_insn ("sll   2,15", s390_profile);                    \
+	  s390_profile[8] = GEN_INT (bo&0x7fff);                           \
+          output_asm_insn ("ahi   2,%8", s390_profile);                    \
+        }                                                                  \
+        output_asm_insn ("a     2,%7", s390_profile);     	     	   \
+        if (flag_pic)							   \
+          output_asm_insn ("l     3,0(2,13)", s390_profile);           	   \
+        else                                                               \
+          output_asm_insn ("l     3,0(2)", s390_profile);     	     	   \
+        output_asm_insn ("ahi   3,1", s390_profile);         	     	   \
+        if (flag_pic)							   \
+          output_asm_insn ("st    3,0(2,13)", s390_profile);          	   \
+        else                                                               \
+          output_asm_insn ("st    3,0(2)", s390_profile);     	     	   \
+	break;								   \
+      }									   \
+    output_asm_insn ("lm    14,5,96(15)", s390_profile);                   \
+    output_asm_insn ("ahi   15,128", s390_profile);		           \
+    output_asm_insn ("spm   14", s390_profile);				   \
+  } while (0)
+
+
+/* The following macro shall output assembler code to FILE
+   to indicate a return from function during basic-block profiling.
+
+   If profiling_block_flag == 2:
+
+	Output assembler code to call function `__bb_trace_ret'.
+
+	Note that function `__bb_trace_ret' must not change the
+	machine state, especially the flag register. To grant
+	this, you must output code to save and restore registers
+	either in this macro or in the macros MACHINE_STATE_SAVE_RET
+	and MACHINE_STATE_RESTORE_RET. The last two macros will be
+	used in the function `__bb_trace_ret', so you must make
+	sure that the function prologue does not change any 
+	register prior to saving it with MACHINE_STATE_SAVE_RET.
+
+   else if profiling_block_flag != 0:
+
+	The macro will not be used, so it need not distinguish
+	these cases.
+*/
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
+do {                                                                       \
+    extern rtx s390_profile[];						   \
+    fprintf (FILE, "# block profiler exit \n");                            \
+    output_asm_insn ("ipm   14", s390_profile);     		    	   \
+    output_asm_insn ("ahi   15,-128", s390_profile);     	       	   \
+    output_asm_insn ("stm   14,5,96(15)", s390_profile);     		   \
+    output_asm_insn ("l     4,%3", s390_profile);		      	   \
+    if (flag_pic)							   \
+      output_asm_insn ("bas   14,0(4,13)", s390_profile);	           \
+    else								   \
+      output_asm_insn ("basr  14,4", s390_profile);	                   \
+    output_asm_insn ("lm    14,5,96(15)", s390_profile);                   \
+    output_asm_insn ("ahi   15,128", s390_profile);		           \
+    output_asm_insn ("spm   14", s390_profile);				   \
+} while (0)
+
+/* The function `__bb_trace_func' is called in every basic block
+   and is not allowed to change the machine state. Saving (restoring)
+   the state can either be done in the BLOCK_PROFILER macro,
+   before calling function (rsp. after returning from function)
+   `__bb_trace_func', or it can be done inside the function by
+   defining the macros:
+
+	MACHINE_STATE_SAVE(ID)
+	MACHINE_STATE_RESTORE(ID)
+
+   In the latter case care must be taken, that the prologue code
+   of function `__bb_trace_func' does not already change the
+   state prior to saving it with MACHINE_STATE_SAVE.
+
+   The parameter `ID' is a string identifying a unique macro use.
+
+   On the s390 all save/restore is done in macros above
+*/
+
+/*
+#define MACHINE_STATE_SAVE(ID) \
+      fprintf (FILE, "\tahi   15,-128 # save state\n");			  \
+      fprintf (FILE, "\tstm   14,5,96(15)\n");				  \
+
+#define MACHINE_STATE_RESTORE(ID) \
+      fprintf (FILE, "\tlm    14,5,96(15) # restore state\n");            \
+      fprintf (FILE, "\tahi   15,128\n");		 		  \
+*/
+
+
+/* Define EXIT_IGNORE_STACK if, when returning from a function, the stack
+   pointer does not matter (provided there is a frame pointer).  */
+
+#define EXIT_IGNORE_STACK       1
+
+/* Addressing modes, and classification of registers for them.  */
+
+/* #define HAVE_POST_INCREMENT */
+/* #define HAVE_POST_DECREMENT */
+
+/* #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
+   reg currently allocated to a suitable hard reg.
+   These definitions are NOT overridden anywhere.  */
+
+#define REGNO_OK_FOR_INDEX_P(REGNO)                                     \
+  (((REGNO) > 0 && (REGNO) < 16) || (REGNO) == ARG_POINTER_REGNUM       \
+    || (reg_renumber[REGNO] > 0 && reg_renumber[REGNO] < 16))
+
+#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_INDEX_P (REGNO)
+
+#define REGNO_OK_FOR_DATA_P(REGNO)                                      \
+  ((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16)
+
+#define REGNO_OK_FOR_FP_P(REGNO)                                        \
+  ((REGNO) > 15 && (REGNO) < FIRST_PSEUDO_REGISTER)
+
+/* Now macros that check whether X is a register and also,
+   strictly, whether it is in a specified class.  */
+
+/* 1 if X is a data register.  */
+
+#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X)))
+
+/* 1 if X is an fp register.  */
+
+#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
+
+/* 1 if X is an address register.  */
+
+#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
+
+/* Maximum number of registers that can appear in a valid memory address.  */
+
+#define MAX_REGS_PER_ADDRESS 2
+
+/* Recognize any constant value that is a valid address.  */
+
+#define CONSTANT_ADDRESS_P(X) 0
+
+/* General operand is everything except SYMBOL_REF, CONST and CONST_DOUBLE
+   they have to be forced to constant pool
+   CONST_INT have to be forced into constant pool, if greater than
+   64k. Depending on the insn they have to be force into constant pool
+   for smaller value; in this case we have to work with nonimmediate operand.  */
+
+#define LEGITIMATE_PIC_OPERAND_P(X)  \
+     legitimate_pic_operand_p (X)
+
+/* Nonzero if the constant value X is a legitimate general operand.
+   It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+
+#define LEGITIMATE_CONSTANT_P(X) \
+     legitimate_constant_p (X)
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check
+   its validity for a certain class.  We have two alternate definitions
+   for each of them.  The usual definition accepts all pseudo regs; the
+   other rejects them all.  The symbol REG_OK_STRICT causes the latter
+   definition to be used.
+
+   Most source files want to accept pseudo regs in the hope that they will
+   get allocated to the class that the insn wants them to be in.
+   Some source files that are used after register allocation
+   need to be strict.  */
+
+#ifndef REG_OK_STRICT
+
+
+/* 
+ * Nonzero if X is a hard reg that can be used as an index or if it is
+ * a pseudo reg.  
+ */
+
+#define REG_OK_FOR_INDEX_P(X)                                           \
+  ((REGNO(X) > 0 && REGNO(X) < 16) || REGNO(X) >= FIRST_PSEUDO_REGISTER-1)
+
+
+/* Nonzero if X is a hard reg that can be used as a base reg or if it is
+   a pseudo reg.  */
+
+#define REG_OK_FOR_BASE_P(X)    REG_OK_FOR_INDEX_P (X)
+
+#else /* REG_OK_STRICT */
+
+/* Nonzero if X is a hard reg that can be used as an index.  */
+
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+
+/* Nonzero if X is a hard reg that can be used as a base reg.  */
+
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#endif /* REG_OK_STRICT */
+
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a
+   valid memory address for an instruction.
+   The MODE argument is the machine mode for the MEM expression
+   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.  */
+
+#define COUNT_REGS(X, REGS, FAIL)                                       \
+ if (REG_P (X) && REG_OK_FOR_BASE_P (X))                                \
+   REGS += 1;                                                           \
+ else if (GET_CODE (X) != CONST_INT || (unsigned) INTVAL (X) >= 4096)   \
+   goto FAIL;
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                         \
+{                                                                       \
+  if (REG_P (X) && REG_OK_FOR_BASE_P (X))                               \
+    goto ADDR;                                                          \
+  if (GET_CODE (X) == PLUS)                                             \
+    {                                                                   \
+      int regs = 0;                                                     \
+      rtx x0 = XEXP (X, 0);                                             \
+      rtx x1 = XEXP (X, 1);                                             \
+      if (GET_CODE (x0) == PLUS)                                        \
+        {                                                               \
+          COUNT_REGS (XEXP (x0, 0), regs, FAIL);                        \
+          COUNT_REGS (XEXP (x0, 1), regs, FAIL);                        \
+          COUNT_REGS (x1, regs, FAIL);                                  \
+          if (regs == 2)                                                \
+            goto ADDR;                                                  \
+        }                                                               \
+      else if (GET_CODE (x1) == PLUS)                                   \
+        {                                                               \
+          COUNT_REGS (x0, regs, FAIL);                                  \
+          COUNT_REGS (XEXP (x1, 0), regs, FAIL);                        \
+          COUNT_REGS (XEXP (x1, 1), regs, FAIL);                        \
+          if (regs == 2)                                                \
+            goto ADDR;                                                  \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          COUNT_REGS (x0, regs, FAIL);                                  \
+          COUNT_REGS (x1, regs, FAIL);                                  \
+          if (regs != 0)                                                \
+            goto ADDR;                                                  \
+        }                                                               \
+    }                                                                   \
+  else if (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(X))    \
+      goto ADDR;                                                        \
+  else if (GET_CODE (X) == CONST &&                                     \
+	         CONSTANT_POOL_ADDRESS_P(XEXP (XEXP (X, 0), 0)))        \
+      goto ADDR;                                                        \
+  FAIL: ;                                                               \
+}
+
+
+/* S/390 has no mode dependent addresses.  */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
+
+/* 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.  */
+
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)                          \
+{                                                                       \
+  if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1)))         \
+    (X) = gen_rtx_PLUS (SImode, XEXP (X, 0),                            \
+                   copy_to_mode_reg (SImode, XEXP (X, 1)));             \
+  if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0)))         \
+    (X) = gen_rtx_PLUS (SImode, XEXP (X, 1),                            \
+                   copy_to_mode_reg (SImode, XEXP (X, 0)));             \
+  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT)           \
+    (X) = gen_rtx_PLUS (SImode, XEXP (X, 1),                            \
+                   force_operand (XEXP (X, 0), 0));                     \
+  if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT)           \
+    (X) = gen_rtx_PLUS (SImode, XEXP (X, 0),                            \
+                   force_operand (XEXP (X, 1), 0));                     \
+  if (GET_CODE (X) == CONST_INT)                                        \
+    (X) = force_const_mem (SImode, (X));                                \
+  if (memory_address_p (MODE, X))                                       \
+    goto WIN;                                                           \
+}
+
+/* Specify the machine mode that this machine uses for the index in the
+   tablejump instruction.  */
+
+#define CASE_VECTOR_MODE SImode
+
+/* 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 */
+
+/* Load from integral MODE < SI from memory into register makes sign_extend
+   or zero_extend  
+   In our case sign_extension happens for Halfwords, other no extension.  */
+
+#define LOAD_EXTEND_OP(MODE)  \
+   ((MODE) == HImode ? SIGN_EXTEND : NIL)
+
+/* Specify the tree operation to be used to convert reals to integers.  */
+
+#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+
+/* Define this if fixuns_trunc is the same as fix_trunc.  */
+
+/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */
+
+/* We use "unsigned char" as default.  */
+
+#define DEFAULT_SIGNED_CHAR 0
+
+/* This is the kind of divide that is easiest to do in the general case.  */
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* Max number of bytes we can move from memory to memory in one reasonably
+   fast instruction.  */
+
+#define MOVE_MAX 256
+
+/* Define this if zero-extension is slow (more than one real instruction).  */
+
+#define SLOW_ZERO_EXTEND
+
+/* Nonzero if access to memory by bytes is slow and undesirable.  */
+
+#define SLOW_BYTE_ACCESS 1
+
+/* Define if shifts truncate the shift count which implies one can omit
+   a sign-extension or zero-extension of a shift count.  */
+
+/* #define SHIFT_COUNT_TRUNCATED */
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+   is done just by pretending it is already truncated.  */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC)  1
+
+/* We assume that the store-condition-codes instructions store 0 for false
+   and some other value for true.  This is the value stored for true.  */
+
+/* #define STORE_FLAG_VALUE -1 */
+
+/* When a prototype says `char' or `short', really pass an `int'.  */
+
+#define PROMOTE_PROTOTYPES 1
+
+/* Don't perform CSE on function addresses.  */
+
+#define NO_FUNCTION_CSE
+
+/* Specify the machine mode that pointers have.
+   After generation of rtl, the compiler makes no further distinction
+   between pointers and any other objects of this machine mode.  */
+
+#define Pmode SImode
+
+/* A function address in a call instruction is a byte address (for
+   indexing purposes) so give the MEM rtx a byte's mode.  */
+
+#define FUNCTION_MODE QImode
+
+
+/* A part of a C `switch' statement that describes the relative costs
+   of constant RTL expressions.  It must contain `case' labels for
+   expression codes `const_int', `const', `symbol_ref', `label_ref'
+   and `const_double'.  Each case must ultimately reach a `return'
+   statement to return the relative cost of the use of that kind of
+   constant value in an expression.  The cost may depend on the
+   precise value of the constant, which is available for examination
+   in X, and the rtx code of the expression in which it is contained,
+   found in OUTER_CODE.
+
+   CODE is the expression code--redundant, since it can be obtained
+   with `GET_CODE (X)'.  */
+/* Force_const_mem does not work out of reload, because the saveable_obstack
+   is set to reload_obstack, which does not live long enough. 
+   Because of this we cannot use force_const_mem in addsi3.
+   This leads to problems with gen_add2_insn with a constant greater
+   than a short. Because of that we give a addition of greater
+   constants a cost of 3 (reload1.c 10096).  */
+
+
+#define CONST_COSTS(RTX, CODE, OUTER_CODE)                      \
+  case CONST:                                                   \
+    if ((GET_CODE (XEXP (RTX, 0)) == MINUS) &&                  \
+	(GET_CODE (XEXP (XEXP (RTX, 0), 1)) != CONST_INT))      \
+     return 1000;                                               \
+  case CONST_INT:                                               \
+       if ((OUTER_CODE == PLUS) &&                              \
+	   ((INTVAL (RTX) > 32767) ||                           \
+	   (INTVAL (RTX) < -32768))) 	                        \
+         return 3;                                              \
+  case LABEL_REF:                                               \
+  case SYMBOL_REF:                                              \
+  case CONST_DOUBLE:                                            \
+    return 1;                                                   \
+
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+   This can be used, for example, to indicate how costly a multiply
+   instruction is.  In writing this macro, you can use the construct
+   `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+   instructions.  OUTER_CODE is the code of the expression in which X
+   is contained.
+
+   This macro is optional; do not define it if the default cost
+   assumptions are adequate for the target machine.  */
+
+#define RTX_COSTS(X, CODE, OUTER_CODE)                                  \
+  case ASHIFT:                                                          \
+  case ASHIFTRT:                                                        \
+  case LSHIFTRT:                                                        \
+  case PLUS:                                                            \
+  case AND:                                                             \
+  case IOR:                                                             \
+  case XOR:                                                             \
+  case MINUS:                                                           \
+  case NEG:                                                             \
+  case NOT:                                                             \
+          return 1;                                                     \
+  case MULT:                                                            \
+    if (GET_MODE (XEXP (X, 0)) == DImode)                               \
+      return 40;                                                        \
+        else                                                            \
+      return 7;                                                         \
+  case DIV:                                                             \
+  case UDIV:                                                            \
+  case MOD:                                                             \
+  case UMOD:                                                            \
+          return 33;
+
+
+/* An expression giving the cost of an addressing mode that contains
+   ADDRESS.  If not defined, the cost is computed from the ADDRESS
+   expression and the `CONST_COSTS' values.
+
+   For most CISC machines, the default cost is a good approximation
+   of the true cost of the addressing mode.  However, on RISC
+   machines, all instructions normally have the same length and
+   execution time.  Hence all addresses will have equal costs.
+
+   In cases where more than one form of an address is known, the form
+   with the lowest cost will be used.  If multiple forms have the
+   same, lowest, cost, the one that is the most complex will be used.
+
+   For example, suppose an address that is equal to the sum of a
+   register and a constant is used twice in the same basic block.
+   When this macro is not defined, the address will be computed in a
+   register and memory references will be indirect through that
+   register.  On machines where the cost of the addressing mode
+   containing the sum is no higher than that of a simple indirect
+   reference, this will produce an additional instruction and
+   possibly require an additional register.  Proper specification of
+   this macro eliminates this overhead for such machines.
+
+   Similar use of this macro is made in strength reduction of loops.
+
+   ADDRESS need not be valid as an address.  In such a case, the cost
+   is not relevant and can be any value; invalid addresses need not be
+   assigned a different cost.
+
+   On machines where an address involving more than one register is as
+   cheap as an address computation involving only one register,
+   defining `ADDRESS_COST' to reflect this can cause two registers to
+   be live over a region of code where only one would have been if
+   `ADDRESS_COST' were not defined in that manner.  This effect should
+   be considered in the definition of this macro.  Equivalent costs
+   should probably only be given to addresses with different numbers
+   of registers on machines with lots of registers.
+
+   This macro will normally either not be defined or be defined as a
+   constant.
+
+   On s390 symbols are expensive if compiled with fpic
+   lifetimes.  */
+
+#define ADDRESS_COST(RTX) \
+  ((flag_pic && GET_CODE (RTX) == SYMBOL_REF) ? 2 : 1)
+
+/* On s390, copy between fprs and gprs is expensive.  */
+
+#define REGISTER_MOVE_COST(CLASS1, CLASS2)                              \
+  (((CLASS1 != CLASS2) &&                                               \
+   (CLASS1 == FP_REGS || CLASS2 == FP_REGS)) ? 10 : 1)
+
+
+/* A C expression for the cost of moving data of mode M between a
+   register and memory.  A value of 2 is the default; this cost is
+   relative to those in `REGISTER_MOVE_COST'.
+
+   If moving between registers and memory is more expensive than
+   between two registers, you should define this macro to express the
+   relative cost.  */
+
+#define MEMORY_MOVE_COST(M, C, I) 1
+
+/* A C expression for the cost of a branch instruction.  A value of 1
+   is the default; other values are interpreted relative to that.  */
+
+#define BRANCH_COST 1
+
+/* Tell final.c how to eliminate redundant test instructions.  */
+
+/* Here we define machine-dependent flags and fields in cc_status
+   (see `conditions.h').  */
+
+/* Store in cc_status the expressions that the condition codes will
+   describe after execution of an instruction whose pattern is EXP.
+   Do not alter them if the instruction would not alter the cc's.
+
+   All information, if cc is to alter or not, is kept in the
+   maschine-description. It is hold within the cc-attributs
+*/
+#define NOTICE_UPDATE_CC(EXP, INSN)                                     \
+     update_cc (EXP, INSN)
+
+
+#define CC_STATUS_SET(V1, V2)                                           \
+{                                                                       \
+  cc_status.flags = 0;                                                  \
+  cc_status.value1 = (V1);                                              \
+  cc_status.value2 = (V2);                                              \
+  if (cc_status.value1                                                  \
+      && reg_mentioned_p (cc_status.value1, cc_status.value2))          \
+    cc_status.value2 = 0;                                               \
+}
+
+#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV)                               \
+{ if (cc_status.flags & CC_NO_OVERFLOW) return NO_OV; return NORMAL; }
+
+
+/* How to refer to registers in assembler output.  This sequence is
+   indexed by compiler's hard-register-number (see above).  */
+
+#ifndef IEEE_FLOAT
+#define REGISTER_NAMES                                                  \
+{ "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",                        \
+  "8",  "9", "10", "11", "12", "13", "14", "15",                        \
+  "0",  "2",  "4",  "6"                                                 \
+}
+#else
+#define REGISTER_NAMES                                                  \
+{ "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",                        \
+  "8",  "9", "10", "11", "12", "13", "14", "15",                        \
+  "0",  "2",  "4",  "6",  "1",  "3",  "5",  "7",                        \
+  "8",  "10", "12", "14", "9", "11", "13", "15", "ap"                   \
+}
+#endif
+
+/* implicit call of memcpy, not bcopy   */
+
+#define TARGET_MEM_FUNCTIONS
+
+
+/* Define results of standard character escape sequences.  */
+
+#define TARGET_BELL     (0x07)
+#define TARGET_BS       (0x08)
+#define TARGET_TAB      (0x09)
+#define TARGET_NEWLINE  (0x0A)
+#define TARGET_VT       11
+#define TARGET_FF       12
+#define TARGET_CR       13
+
+/* Print operand X (an rtx) in assembler syntax to file FILE.
+   CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
+   For `%' followed by punctuation, CODE is the punctuation and X is null.  */
+
+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+
+
+/* Define the codes that are matched by predicates in aux-output.c.  */
+
+#define PREDICATE_CODES                                                 \
+  {"general_pmode_operand", { CONST_INT, SYMBOL_REF, SUBREG, REG, MEM }},\
+  {"add_operand",     { REG, MEM, CONST_INT }},                          \
+  {"sm_operand",      { SUBREG, MEM }},                                  \
+  {"s_operand",       { MEM }},                                          \
+  {"bras_sym_operand",{ SYMBOL_REF }},                                   \
+  {"r_or_s_operand",  { MEM, SUBREG, REG }},                             \
+  {"r_or_im8_operand",  { CONST_INT, SUBREG, REG }},                     \
+  {"r_or_s_or_im8_operand",  { MEM, SUBREG, REG, CONST_INT }},           \
+  {"r_or_x_or_im16_operand", { MEM, SUBREG, REG, CONST_INT }},              
+
+
+/* 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.  */
+
+#define ADJUST_COST(insn, link, dep_insn, cost) \
+  (cost) = s390_adjust_cost (insn, link, dep_insn, cost)
+
+
+/* Constant Pool for all symbols operands which are changed with
+   force_const_mem during insn generation (expand_insn).  */
+
+extern struct rtx_def *s390_pool_start_insn;
+extern int s390_pool_count;
+
+/* Function is splitted in chunk, if literal pool could overflow
+   Value need to be lowered, if problems with displacement overflow.  */
+
+#define S390_REL_MAX 55000
+#define S390_CHUNK_MAX 0x4000
+#define S390_CHUNK_OV 0x1000
+#define S390_POOL_MAX 3000
+
+#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size)  	        \
+{								       	\
+  register rtx insn;						       	\
+  struct pool_constant *pool;					       	\
+								        \
+    if (s390_pool_count == -1)                                        	\
+      return;                                                           \
+    if (first_pool == 0) {                                              \
+      s390_asm_output_pool_prologue (FILE, FUNNAME, fndecl, size);    	\
+      return;							      	\
+    }								       	\
+    for (pool = first_pool; pool; pool = pool->next)		       	\
+      pool->mark = 0;						       	\
+  								       	\
+    insn = s390_pool_start_insn;				       	\
+  								       	\
+    if (insn==NULL_RTX)	 					       	\
+      insn = get_insns ();		 		                \
+    else		       			                        \
+      insn = NEXT_INSN (insn);		                                \
+    for (; insn; insn = NEXT_INSN (insn)) {    		                \
+      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') {		       	\
+        if (s390_stop_dump_lit_p (insn)) { 	       		       	\
+	  mark_constants (PATTERN (insn));			       	\
+	  break;						       	\
+        } else							       	\
+	  mark_constants (PATTERN (insn));			       	\
+      }								       	\
+    }								       	\
+								       	\
+    for (pool = first_pool; pool; pool = pool->next)		       	\
+      {								       	\
+        struct pool_sym *sym;					       	\
+        char *label;						       	\
+      								       	\
+        /* skip unmarked entries; no insn refers to them.  */	       	\
+        if (! pool->mark)					       	\
+	  continue;						       	\
+      								       	\
+        label = XSTR (pool->constant, 0);			       	\
+      								       	\
+        /* Be sure the symbol's value is marked.  */		       	\
+        for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym;     	\
+             sym = sym->next)					       	\
+	  if (sym->label == label)				       	\
+	    sym->pool->mark = 1;				       	\
+        /* If we didn't find it, there's something truly wrong here, but it \
+	   will be announced by the assembler.  */			\
+      }								       	\
+      s390_asm_output_pool_prologue (FILE, FUNNAME, fndecl, size);     	\
+}
+
+/* We need to return, because otherwise the pool is deleted of the 
+   constant pool after the first output.  */
+
+#define ASM_OUTPUT_POOL_EPILOGUE(FILE, FUNNAME, fndecl, size) return;
+
+#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, EXP, MODE, ALIGN, LABELNO, WIN) \
+{                                                                       \
+  if ((s390_pool_count == 0) || (s390_pool_count > 0 && LABELNO >= 0)) {\
+    fprintf (FILE, ".LC%d:\n", LABELNO);                                \
+    LABELNO = ~LABELNO;                                                 \
+  }                                                                     \
+  if (s390_pool_count > 0)                                      {       \
+    fprintf (FILE, ".LC%d_%X:\n", ~LABELNO, s390_pool_count);           \
+  }                                                                     \
+  s390_output_const (FILE, EXP, MODE);                                  \
+  fputc ('\n', FILE);                                                   \
+  goto WIN;                                                             \
+}
+
+#endif 


More information about the Gcc-patches mailing list