This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

gcc S/390 backend 1


Hi,
	Part 1 of changed S/390 backend

2000-10-09  Hartmut Penner  <hpenner@de.ibm.com>

	* configure.in: Add new target s390-ibm-linux-gnu.
	* config/mt-s390pic: New file.
	* config/mh-s390pic: New file.
	* gcc/config/s390/s390.md: New file, S/390 machine description.
	* gcc/config/s390/s390.h: New file, S/390 basic target macros. 
	* gcc/config/s390/linux.h: New file, S/390 linux target macros.
	* gcc/config/s390/s390.c: New file, S/390 basic target functions. 
	* gcc/config/s390/linux.c: New file, S/390 linux target functions.
	* gcc/config/s390/t-linux: New file.
	* gcc/config/s390/xm-s390: New file.
diff -r -u --new-file egcs-20001002/config/mh-s390pic egcs-20001002-s390/config/mh-s390pic
--- egcs-20001002/config/mh-s390pic	Thu Jan  1 01:00:00 1970
+++ egcs-20001002-s390/config/mh-s390pic	Fri Oct  6 12:53:33 2000
@@ -0,0 +1 @@
+PICFLAG=-fpic
diff -r -u --new-file egcs-20001002/config/mt-s390pic egcs-20001002-s390/config/mt-s390pic
--- egcs-20001002/config/mt-s390pic	Thu Jan  1 01:00:00 1970
+++ egcs-20001002-s390/config/mt-s390pic	Fri Oct  6 12:53:33 2000
@@ -0,0 +1 @@
+PICFLAG_FOR_TARGET=-fpic
diff -r -u --new-file egcs-20001002/gcc/config/s390/linux.c egcs-20001002-s390/gcc/config/s390/linux.c
--- egcs-20001002/gcc/config/s390/linux.c	Thu Jan  1 01:00:00 1970
+++ egcs-20001002-s390/gcc/config/s390/linux.c	Mon Oct  9 17:20:22 2000
@@ -0,0 +1,1056 @@
+/* Subroutines used for code generation on linux on 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 "except.h"
+#include "function.h"
+#include "recog.h"
+#include "expr.h"
+#include "math.h"
+
+#include "tm.h"
+#include "tm_p.h"
+
+
+#ifdef DWARF2_DEBUGGING_INFO
+extern char *dwarf2out_cfi_label PARAMS ((void));
+#endif
+
+/* Flag set in prologue, used in epilog to know
+  if stack is allocated or not.  */
+
+static int leaf_function_flag;
+rtx s390_got_label;
+rtx s390_profile[10];
+
+/* Current function is a leaf function, without automatics,
+   alloca or vararg stuff.  */
+
+static int
+cur_is_leaf_function ()
+{
+  int lsize =  get_frame_size () + current_function_outgoing_args_size;
+  if (leaf_function_p () && ((lsize) == 0) &&
+      ! (current_function_calls_alloca) &&
+      ! (current_function_stdarg) && ! (current_function_varargs))
+    return 1;
+  return 0;
+}
+
+/* Calculate offset between argument pointer and frame pointer 
+   initialy after prologue.  */
+
+int s390_arg_frame_offset ()
+{
+  int lsize =  get_frame_size () + current_function_outgoing_args_size;
+
+  if (cur_is_leaf_function ())
+    return STACK_POINTER_OFFSET;
+  else
+    return 2*STACK_POINTER_OFFSET + lsize;
+}
+
+
+/* This function generates the assembly code for function entry.  */
+
+int
+s390_function_prologue (FILE * file, int lsize)
+{
+  extern int profile_label_no;
+  int i, j, so;
+  rtx stack_label = 0, got_label = 0, tmp;
+  char *l;
+
+  /* Profile code (-p, -a, -ax needs some literals).  */
+
+  if (profile_block_flag)
+    {
+      tmp = gen_rtx (SYMBOL_REF, Pmode, &"F@__bb_init_func"[1]);
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[0] = force_const_mem  (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[0]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, &"F@__bb_init_trace_func"[1]);
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[1] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[1]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, &"F@__bb_trace_func"[1]);
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[2] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[2]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, &"F@__bb_trace_ret"[1]);
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[3] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[3]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, "__bb");
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[5] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[5]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, ".LPBX0");
+      s390_profile[6] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[6]), get_insns ());
+
+      tmp = gen_rtx (SYMBOL_REF, Pmode, ".LPBX2");
+      s390_profile[7] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[7]), get_insns ());
+    }
+
+  if (profile_flag)
+    {
+      static char label[128];
+      tmp = gen_rtx (SYMBOL_REF, Pmode, &"F@_mcount"[1]);
+      SYMBOL_REF_FLAG (tmp) = 1;
+      s390_profile[4] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[4]), get_insns ());
+      sprintf (label, "%sP%d", LPREFIX, profile_label_no);
+      tmp = gen_rtx (SYMBOL_REF, Pmode, label);
+      s390_profile[9] = force_const_mem (Pmode, tmp);
+      emit_insn_before (gen_rtx (USE, Pmode, s390_profile[9]), get_insns ());
+    }
+
+  if (get_pool_size () > S390_POOL_MAX)
+    s390_final_chunkify (1);
+  else
+    s390_final_chunkify (0);
+
+  if (current_function_uses_pic_offset_table)
+    {
+
+      got_label = force_const_mem (Pmode,
+				   gen_rtx (SYMBOL_REF, Pmode,
+					    &"i@_GLOBAL_OFFSET_TABLE_"[2]));
+      emit_insn_before (gen_rtx (USE, Pmode, got_label), get_insns ());
+    }
+
+  if ((so = STARTING_FRAME_OFFSET + lsize) > 0x7fff)
+    {
+
+      stack_label = force_const_mem (Pmode, gen_rtx_CONST_INT (Pmode, so));
+      emit_insn_before (gen_rtx (USE, Pmode, stack_label), get_insns ());
+    }
+
+ if (cur_is_leaf_function ())
+   {
+      leaf_function_flag = 1;
+      fprintf (file, "%s\tleaf function\n", ASM_COMMENT_START);
+      fprintf (file, "%s\thas varargs             %d\n", ASM_COMMENT_START,
+	       current_function_stdarg);
+      fprintf (file, "%s\tincoming args (stack)   %d\n", ASM_COMMENT_START,
+	       current_function_args_size);
+      fprintf (file, "%s\tfunction length         %d\n", ASM_COMMENT_START,
+	       insn_current_address);
+      
+      /* Save gprs 6 - 15 and fprs 4 and 6.  */
+      if (flag_pic)
+	for (i = 6; i < 12 && (regs_ever_live[i] == 0); i++);
+      else
+	for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
+
+      if (! (! flag_pic && i == 13 &&
+	    regs_ever_live[14] == 0 && ! get_pool_size ()))
+	{
+	  fprintf (file, "\tSTM\t%d,14,%d(%d)\n", i, i * 4,
+		   STACK_POINTER_REGNUM);
+#ifdef INCOMING_RETURN_ADDR_RTX
+	  if (dwarf2out_do_frame ())
+	    {
+	      l = dwarf2out_cfi_label ();
+	      dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, 
+				 STACK_POINTER_OFFSET);
+	      for (j = i; j <= 14; j++)
+		dwarf2out_reg_save (l, j, (j-24)*4);
+	      if (regs_ever_live[18])
+		dwarf2out_reg_save (l, 18, -16);
+	      if (regs_ever_live[19])
+		dwarf2out_reg_save (l, 19, -8);
+	    }
+
+#endif
+	}
+
+      /* Output constant pool.  */
+      if (get_pool_size ())
+	{
+	  s390_pool_count = 0;
+	  fprintf (file, "\tBRAS\t%d,.LTN%X_%X\n", BASE_REGISTER,
+		   s390_function_count, s390_pool_count);
+	  fprintf (file, ".LT%X_%X:\n", s390_function_count, s390_pool_count);
+	  output_constant_pool (current_function_name, current_function_decl);
+	  fprintf (file, ".LTN%X_%X:\n", s390_function_count,
+		   s390_pool_count);
+	  regs_ever_live[BASE_REGISTER] = 1;
+	}
+
+      /* Save fprs.  */
+
+      if (regs_ever_live[18])
+	fprintf (file, "\tSTD\t4,80(%d)\n", STACK_POINTER_REGNUM);
+      if (regs_ever_live[19])
+	fprintf (file, "\tSTD\t6,88(%d)\n", STACK_POINTER_REGNUM);
+
+    }
+  else
+    {				/* No leaf function.  */
+      fprintf (file, "%s\tleaf function           %d\n", ASM_COMMENT_START,
+	       leaf_function_p ());
+      fprintf (file, "%s\tautomatics              %d\n", ASM_COMMENT_START,
+	       lsize);
+      fprintf (file, "%s\toutgoing args           %d\n", ASM_COMMENT_START,
+	       current_function_outgoing_args_size);
+      fprintf (file, "%s\tneed frame pointer      %d\n", ASM_COMMENT_START,
+	       frame_pointer_needed);
+      fprintf (file, "%s\tcall alloca             %d\n", ASM_COMMENT_START,
+	       current_function_calls_alloca);
+      fprintf (file, "%s\thas varargs             %d\n", ASM_COMMENT_START,
+	       current_function_stdarg || current_function_varargs);
+      fprintf (file, "%s\tincoming args (stack)   %d\n", ASM_COMMENT_START,
+	       current_function_args_size);
+      fprintf (file, "%s\tfunction length         %d\n", ASM_COMMENT_START,
+	       insn_current_address);
+
+      /* Save gprs 6 - 15 and fprs 4 and 6.  */
+      
+      if (current_function_stdarg || current_function_varargs)
+	{
+	  i = 2;
+	}
+      else
+	{
+	  for (i = 6; i < 11 && (regs_ever_live[i] == 0); i++);
+	}
+
+      fprintf (file, "\tSTM\t%d,15,%d(%d)\n", i, i * 4, STACK_POINTER_REGNUM);
+
+#ifdef INCOMING_RETURN_ADDR_RTX
+      if (dwarf2out_do_frame ())
+	{
+	  l = dwarf2out_cfi_label ();
+	  dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, STACK_POINTER_OFFSET);
+	  for (j = i; j <= 15; j++)
+	    dwarf2out_reg_save (l, j, (j-24)*4);
+	  if (regs_ever_live[18])
+	    dwarf2out_reg_save (l, 18, -16);
+	  if (regs_ever_live[19])
+	    dwarf2out_reg_save (l, 19, -8);
+	}
+#endif
+
+
+      /* Output constant pool.  */
+
+      if (get_pool_size ())
+	{
+	  s390_pool_count = 0;
+	  fprintf (file, "\tBRAS\t%d,.LTN%X_%X\n", BASE_REGISTER,
+		   s390_function_count, s390_pool_count);
+	  fprintf (file, ".LT%X_%X:\n", s390_function_count, s390_pool_count);
+	  output_constant_pool (current_function_name, current_function_decl);
+	  fprintf (file, ".LTN%X_%X:\n", s390_function_count,
+		   s390_pool_count);
+	}
+
+      /* Save fprs.  */
+
+      if (current_function_stdarg || current_function_varargs)
+	{
+	  fprintf (file, "\tSTD\t0,64(%d)\n", STACK_POINTER_REGNUM);
+	  fprintf (file, "\tSTD\t2,72(%d)\n", STACK_POINTER_REGNUM);
+	}
+      if (regs_ever_live[18])
+	fprintf (file, "\tSTD\t4,80(%d)\n", STACK_POINTER_REGNUM);
+      if (regs_ever_live[19])
+	fprintf (file, "\tSTD\t6,88(%d)\n", STACK_POINTER_REGNUM);
+
+      /* Decrement stack.  */
+
+      if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET + lsize + 4 * i > 4095
+			       || frame_pointer_needed
+			       || current_function_calls_alloca))
+	{
+
+	  fprintf (file, "\tLR\t1,%d\n", STACK_POINTER_REGNUM);
+	}
+
+      if (stack_label)
+	{
+	  rtx operands[2];
+
+	  operands[0] = gen_rtx (REG, Pmode, 15);
+	  operands[1] = stack_label;
+	  output_asm_insn ("S\t%0,%1", operands);
+	}
+      else
+	{
+	  fprintf (file, "\tAHI\t%d,-%d\n", STACK_POINTER_REGNUM, so);
+	}
+#ifdef INCOMING_RETURN_ADDR_RTX
+      if (dwarf2out_do_frame ())
+	{
+	  if (frame_pointer_needed)
+	    dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM,
+			       STACK_POINTER_OFFSET+so);
+	  else
+	    dwarf2out_def_cfa ("", STACK_POINTER_REGNUM,
+			       STACK_POINTER_OFFSET+so);
+	}
+#endif
+
+
+      /* Generate backchain.  */
+
+      if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET + lsize + 4 * i > 4095
+			       || frame_pointer_needed
+			       || current_function_calls_alloca))
+	{
+	  fprintf (file, "\tST\t1,0(%d)\n", STACK_POINTER_REGNUM);
+	}
+    }
+
+  if (frame_pointer_needed)
+    {
+      fprintf (file, "\tLR\t%d,%d\n", FRAME_POINTER_REGNUM,
+	       STACK_POINTER_REGNUM);
+    }
+
+  /* Load GOT if used and emit use insn that optimizer does not
+     erase literal pool entry.  */
+
+  if (current_function_uses_pic_offset_table)
+    {
+      rtx operands[3];
+
+      operands[0] = gen_rtx (REG, Pmode, 12);
+      operands[1] = got_label;
+      operands[2] = gen_rtx (REG, Pmode, 13);
+      output_asm_insn ("L\t%0,%1\n\tAR\t%0,%2", operands);
+    }
+  return 0;
+}
+
+/* This function generates the assembly code for function exit.  */
+
+int
+s390_function_epilogue (FILE * file, int lsize)
+{
+/* Register is call clobbered and not used for eh or return.  */
+#define FREE_REG 4
+
+  int i;
+  int return_reg = RETURN_REGNUM;
+  int fp, offset;
+
+  if (leaf_function_flag)
+    {
+      if (flag_pic)
+	for (i = 6; i < 12 && (regs_ever_live[i] == 0); i++);
+      else
+	for (i = 6; i < 13 && (regs_ever_live[i] == 0); i++);
+      if (! (! flag_pic && i == 13 &&
+	    regs_ever_live[14] == 0 && ! get_pool_size ()))
+	{
+	  if (flag_pic > 1)
+	    {
+	      return_reg = FREE_REG;
+	      fprintf (file, "\tL\t%d,56(%d)\n", return_reg,
+		       STACK_POINTER_REGNUM);
+	    }
+	  if (regs_ever_live[18])
+	    fprintf (file, "\tLD\t4,80(%d)\n", STACK_POINTER_REGNUM);
+	  if (regs_ever_live[19])
+	    fprintf (file, "\tLD\t6,88(%d)\n", STACK_POINTER_REGNUM);
+	  if (flag_pic > 1)
+	    fprintf (file, "\tLM\t%d,14,%d(%d)\n", i, 4 * i,
+		     STACK_POINTER_REGNUM);
+	  else
+	    fprintf (file, "\tLM\t%d,13,%d(%d)\n", i, 4 * i,
+		     STACK_POINTER_REGNUM);
+	}
+    }
+  else
+    {
+      for (i = 6; i < 11 && (regs_ever_live[i] == 0); i++);
+
+      if (STARTING_FRAME_OFFSET + lsize + 88 > 4095)    
+	{
+	  offset = 0;
+	  fp = STACK_POINTER_REGNUM;
+	}
+      else if (frame_pointer_needed || current_function_calls_alloca)
+	{
+	  offset = STARTING_FRAME_OFFSET + lsize;
+	  fp = FRAME_POINTER_REGNUM;
+	}
+      else
+	{
+	  offset = STARTING_FRAME_OFFSET + lsize;
+	  fp = STACK_POINTER_REGNUM;
+	}
+      if (offset == 0)
+	fprintf (file, "\tL\t%d,0(%d)\n",fp,fp);
+      return_reg = FREE_REG;
+      fprintf (file, "\tL\t%d,%d(%d)\n",return_reg,56+offset,fp);
+      if (regs_ever_live[18])
+	fprintf (file, "\tLD\t4,%d(%d)\n",80+offset,fp); 
+      if (regs_ever_live[19])
+	fprintf (file, "\tLD\t6,%d(%d)\n",88+offset,fp);
+      
+      fprintf (file, "\tLM\t%d,15,%d(%d)\n", i, (4 * i) + offset,fp);
+    }
+  
+  fprintf (file, "\tBR\t%d\n", return_reg);
+
+  current_function_uses_pic_offset_table = 0;
+  leaf_function_flag = 0;
+  s390_pool_start_insn = NULL_RTX;
+  s390_pool_count = -1;
+  s390_function_count++;
+  return 0;
+}
+
+/* This is epilogue code, maybe should use generic in except.c.  */ 
+
+void
+s390_expand_eh_epilogue (rtx reg1, rtx reg2, rtx reg3)
+{
+  rtx stub_start, after_stub;
+  rtx ra, tmp;
+
+  /* Otherwise, use the same stub technique we had before.  */
+
+  eh_return_stub_label = stub_start = gen_label_rtx ();
+  after_stub = gen_label_rtx ();
+
+  /* Set the return address to the stub label.  */
+
+  ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+				   0, hard_frame_pointer_rtx);
+  if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start));
+
+  tmp = force_operand (tmp, ra);
+  if (tmp != ra)
+    emit_move_insn (ra, tmp);
+
+  /* Indicate that the registers are in fact used.  */
+  emit_insn (gen_rtx_USE (VOIDmode, reg1));
+  emit_insn (gen_rtx_USE (VOIDmode, reg2));
+  emit_insn (gen_rtx_USE (VOIDmode, reg3));
+  if (GET_CODE (ra) == REG)
+    emit_insn (gen_rtx_USE (VOIDmode, ra));
+
+  emit_move_insn (gen_rtx_REG (Pmode, 1), reg3);
+  /* Generate the stub.  */
+
+  emit_jump (after_stub);
+  emit_label (stub_start);
+
+  reg1 = gen_rtx_REG (Pmode, 2);
+
+  emit_indirect_jump (gen_rtx_REG (Pmode, 1));
+
+  emit_label (after_stub);
+}
+
+
+/* For structs of odd size the address is passed as reference. 
+   Complex number are also passes on the stack. 
+
+   Note: We don't use mode, since a struct with the following format 
+   is BLKmode, but has size 4.
+   struct 
+     {
+       char a;
+       char b[3]
+     }. 
+   The ABI states, that this value has to be passed in register.  */
+
+int
+s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
+{
+  int size;
+  if (type)
+    size = int_size_in_bytes (type);
+  else
+    {
+      /* Library call, no type available.  */
+      if (mode == BLKmode)
+	return 1;
+      return 0;
+    }
+
+  if ((AGGREGATE_TYPE_P (type) &&
+       size != 1 &&
+       size != 2 &&
+       size != 4 &&
+       size != 8) ||
+      (TREE_CODE (type) == COMPLEX_TYPE))
+    {
+      return 1;
+    }
+  return 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.).  */
+
+void
+s390_function_arg_advance (CUMULATIVE_ARGS * cum,
+		      enum machine_mode mode, tree type, int named)
+{
+  if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
+    {
+      cum->fprs++;
+    }
+  else if (s390_function_arg_pass_by_reference (mode, type))
+    {
+      cum->gprs += 1;
+    }
+  else
+    {
+      cum->gprs += ((GET_MODE_SIZE (mode) + 3) / 4);
+    }
+}
+
+
+
+/* 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. Gprs 2-6 and Fprs 0 and 2 are used as arguments.
+   All integral values go into register, until all are used up, the rest
+   goes onto stack. The same is valid for floating-point values.  */
+
+struct rtx_def *
+s390_function_arg (CUMULATIVE_ARGS * cum,
+	      enum machine_mode mode, tree type, int named)
+{
+  if (s390_function_arg_pass_by_reference (mode, type))
+      return 0;
+
+  if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
+    {
+      if (cum->fprs > 1)
+	{
+	  return 0;
+	}
+      else
+	return gen_rtx (REG, mode, cum->fprs + 16);
+    }
+  else
+    {
+      if ((cum->gprs > 4) ||
+	  ((mode == DFmode || mode == DImode) && cum->gprs > 3))
+	{
+	  return 0;
+	}
+      else
+	return gen_rtx (REG, mode, cum->gprs + 2);
+    }
+}
+
+
+/* Builtin va_list stuff
+   va_list is a structure of four elements:
+      gpr:  number of named args passed in general purpose register 
+      gpr:  number of named args passed in floating purpose register 
+      overflow_arg_area:  address of area, where arguments are passed
+                          if they do not fit in gprs 2 to 6 and fpr 0 and 2
+      reg_save_area:  address, where register passed args are saved 
+                      in prologue.  */
+
+tree
+s390_build_va_list ()
+{
+  tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
+
+  record = make_lang_type (RECORD_TYPE);
+  type_decl =
+    build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+
+  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"), integer_type_node);
+  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"), integer_type_node);
+  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
+		      ptr_type_node);
+  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
+		      ptr_type_node);
+
+  DECL_FIELD_CONTEXT (f_gpr) = record;
+  DECL_FIELD_CONTEXT (f_fpr) = record;
+  DECL_FIELD_CONTEXT (f_ovf) = record;
+  DECL_FIELD_CONTEXT (f_sav) = record;
+
+  TREE_CHAIN (record) = type_decl;
+  TYPE_NAME (record) = type_decl;
+  TYPE_FIELDS (record) = f_gpr;
+  TREE_CHAIN (f_gpr) = f_fpr;
+  TREE_CHAIN (f_fpr) = f_ovf;
+  TREE_CHAIN (f_ovf) = f_sav;
+
+  layout_type (record);
+
+  /* The correct type is an array type of one element.  */
+  return build_array_type (record, build_index_type (size_zero_node));
+}
+
+/* Builtin va_start 
+   The va_list struct is set with the values.
+   gpr: compile time known got out of  current_function_args_info
+   fpr: compile time known got out of  current_function_args_info
+   overflow_arg_area: address passed with register 7 (incoming args register)
+                  (setup in prologue)
+   reg_save_area: address of save area where first 5 gprs and 2 fprs sare 
+                  saved (saved in prologue).  */
+
+void
+s390_va_start (int stdarg_p, tree valist, rtx nextarg)
+{
+  HOST_WIDE_INT n_gpr, n_fpr;
+  int off;
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, t;
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  /* Count number of gp and fp argument registers used.  */
+
+  n_gpr = current_function_args_info.gprs;
+  n_fpr = current_function_args_info.fprs;
+
+  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the overflow area.  */
+  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+
+  off = INTVAL (current_function_arg_offset_rtx);
+  off = off < 0 ? 0 : off;
+  if (! stdarg_p)
+    off = off > 0 ? off - 4 : off;
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n",
+	     n_gpr, n_fpr, off);
+
+  t = build (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_2 (off, 0));
+
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the register save area.  */
+  t = make_tree (TREE_TYPE (sav), virtual_incoming_args_rtx);
+  t = build (PLUS_EXPR, TREE_TYPE (sav), t,
+	     build_int_2 (-STACK_POINTER_OFFSET, -1));
+  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+
+/* Builtin va_arg.  
+   
+   Works like following:
+   
+   if (integral value) {
+     if (size  <= 4 && args.gpr < 5 ||
+         size  > 4 && args.gpr < 4 ) 
+       ret = args.reg_save_area[args.gpr+8]
+     else
+       ret = *args.overflow_arg_area++;
+   } else if (float value) {
+     if (args.fgpr < 2)
+       ret = args.reg_save_area[args.fpr+64]
+     else
+       ret = *args.overflow_arg_area++;
+   } else if (aggregate value) {
+     if (args.gpr < 5)
+       ret = *args.reg_save_area[args.gpr]
+     else
+       ret = **args.overflow_arg_area++;
+   } */
+
+
+rtx
+s390_va_arg (tree valist, tree type)
+{
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, reg, t, u;
+  int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale, max_reg;
+  rtx lab_false, lab_over, addr_rtx, r;
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  if (s390_function_arg_pass_by_reference (TYPE_MODE (type), type))
+    {
+      if (TARGET_DEBUG_ARG)
+	{
+	  fprintf (stderr, "va_arg: aggregate type");
+	  debug_tree (type);
+	}
+
+      /* Aggregates are passed by reference.  */
+      indirect_p = 1;
+      reg = gpr;
+      n_reg = 1;
+      sav_ofs = 8;
+      sav_scale = 4;
+      size = rsize = UNITS_PER_WORD;
+      max_reg = 5;
+    }
+  else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
+    {
+      if (TARGET_DEBUG_ARG)
+	{
+	  fprintf (stderr, "va_arg: float type");
+	  debug_tree (type);
+	}
+
+      /* FP args go in FP registers, if present.  */
+      indirect_p = 0;
+      reg = fpr;
+      n_reg = 1;
+      sav_ofs = 64;
+      sav_scale = 8;
+      max_reg = 1;
+    }
+  else
+    {
+      if (TARGET_DEBUG_ARG)
+	{
+	  fprintf (stderr, "va_arg: other type");
+	  debug_tree (type);
+	}
+
+      /* Otherwise into GP registers.  */
+      indirect_p = 0;
+      reg = gpr;
+      n_reg = rsize;
+      sav_ofs =
+	TYPE_MODE (type) == HImode ? 10 : TYPE_MODE (type) == QImode ? 11 : 8;
+      sav_scale = 4;
+      if (rsize > 1)
+	max_reg = 3;
+      else
+	max_reg = 4;
+    }
+
+  /* Pull the value out of the saved registers ...  */
+
+  lab_false = gen_label_rtx ();
+  lab_over = gen_label_rtx ();
+  addr_rtx = gen_reg_rtx (Pmode);
+
+
+  emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, SImode, EXPAND_NORMAL),
+			   GEN_INT (max_reg),
+			   GT, const1_rtx, SImode, 0, 1, lab_false);
+
+  if (sav_ofs)
+    t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+  else
+    t = sav;
+
+  u = build (MULT_EXPR, integer_type_node, reg, build_int_2 (sav_scale, 0));
+  TREE_SIDE_EFFECTS (u) = 1;
+
+  t = build (PLUS_EXPR, ptr_type_node, t, u);
+  TREE_SIDE_EFFECTS (t) = 1;
+
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
+
+  u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0));
+  TREE_SIDE_EFFECTS (u) = 1;
+  expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  emit_jump_insn (gen_jump (lab_over));
+  emit_barrier ();
+  emit_label (lab_false);
+
+  /* ... Otherwise out of the overflow area.  */
+
+  t = save_expr (ovf);
+
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
+
+  t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  emit_label (lab_over);
+
+  if (indirect_p)
+    {
+      r = gen_rtx_MEM (Pmode, addr_rtx);
+      MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+      emit_move_insn (addr_rtx, r);
+    }
+
+
+  return addr_rtx;
+}
+
+/* Implementation of Trampoline
+   Gpr 1 is used as base register and for the jump
+   to the nested function. 
+   Gpr 0 is static chain.  */
+
+void
+s390_trampoline_template (FILE * file)
+{
+  fprintf (file, "basr\t1,0\n");
+  fprintf (file, "L\t0,10(1)\n");
+  fprintf (file, "L\t1,14(1)\n");
+  fprintf (file, "BR\t1\n");
+  fprintf (file, ".long\t0\n");
+  fprintf (file, ".long\t0\n");
+}
+
+void
+s390_initialize_trampoline (addr, fnaddr, cxt)
+     rtx addr;
+     rtx fnaddr;
+     rtx cxt;
+{
+  emit_move_insn (gen_rtx (MEM, Pmode,
+			   memory_address (Pmode, plus_constant (addr, 12))),
+		  cxt);
+  emit_move_insn (gen_rtx
+		  (MEM, Pmode,
+		   memory_address (Pmode, plus_constant (addr, 16))), fnaddr);
+}
+
+
+/* Print an integer constant expression in assembler syntax.  Addition
+   and subtraction are the only arithmetic that may appear in these
+   expressions.  FILE is the stdio stream to write to, X is the rtx.  */
+
+void
+output_pic_addr_const (FILE * file, rtx x)
+{
+  char code = ' ';
+  char buf[256];
+  const char *name;
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      if (GET_CODE (x) == SYMBOL_REF)
+	{
+	  if (XSTR (x, 0)[0] == '@')
+	    {
+	      code = 'P';
+	      name = XSTR (x, 0) + 1;
+	    }
+	  else
+	    {
+	      code = XSTR (x, 0)[-2];
+	      name = XSTR (x, 0);
+	    }
+	  assemble_name (asm_out_file,(char*) name);
+	}
+      else
+	{
+
+	  ASM_GENERATE_INTERNAL_LABEL (buf, "L",
+				       CODE_LABEL_NUMBER (XEXP (x, 0)));
+	  assemble_name (asm_out_file, buf);
+	}
+      if (code == 'P')
+	{
+	  fprintf (file, "@PLT-.LT%X_%X",
+		   s390_function_count, s390_pool_count);
+	}
+      else if (SYMBOL_REF_FLAG (x))
+	{
+	  fprintf (file, "@GOT");
+	}
+      else
+	{
+	  fprintf (file, "-.LT%X_%X", s390_function_count, s390_pool_count);
+	}
+      break;
+
+    case CODE_LABEL:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
+      assemble_name (asm_out_file, buf);
+      break;
+
+    case CONST_INT:
+      fprintf (file, "%d", INTVAL (x));
+      break;
+
+    case CONST:
+      output_pic_addr_const (file, XEXP (x, 0));
+      break;
+
+    case PLUS:
+      output_pic_addr_const (file, XEXP (x, 0));
+      fprintf (file, "+");
+      output_pic_addr_const (file, XEXP (x, 1));
+      break;
+
+    case MINUS:
+      output_pic_addr_const (file, XEXP (x, 0));
+      fprintf (file, "-");
+      output_pic_addr_const (file, XEXP (x, 1));
+      break;
+
+    default:
+      output_addr_const (file, x);
+    }
+}
+
+
+void
+s390_output_const (FILE * file, rtx x, enum machine_mode mode)
+{
+
+  char code;
+  REAL_VALUE_TYPE rv;
+
+  if (mode == SFmode)
+    {
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+      ASM_OUTPUT_FLOAT (file, rv);
+    }
+  else if (mode == DFmode)
+    {
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+      ASM_OUTPUT_DOUBLE (file, rv);
+    }
+  else if (mode == HImode)
+    ASM_OUTPUT_SHORT (file, x);
+  else if (mode == DImode)
+    ASM_OUTPUT_DOUBLE_INT (file, x);
+  else
+    {
+      fprintf (file, "%s\t", ASM_LONG);
+      if (flag_pic)
+	{
+	  output_pic_addr_const (file, x);
+	}
+      else
+	{
+	  if ((GET_CODE (x) == SYMBOL_REF) &&
+	      (XSTR (x, 0)[0] == '@') &&
+	      (((code = XSTR (x, 0)[-1]) == 'F') || (code == 'f')))
+	    {
+
+	      assemble_name (file, &XSTR (x, 0)[1]);
+	    }
+	  else
+	    {
+	      output_addr_const (file, x);
+	    }
+	}
+    }
+}
+
+
+
+void
+s390_asm_output_external_libcall (FILE * file, rtx x)
+{
+  char *new_str;
+  new_str = permalloc (strlen (XSTR (x, 0)) + 3);
+  strcpy (new_str + 2, XSTR (x, 0));
+  XSTR (x, 0) = new_str + 2;
+  new_str[0] = 'F';
+  new_str[1] = '@';
+  ASM_GLOBALIZE_LABEL (file, new_str + 2);
+}
+
+int
+legitimate_pic_operand_p (rtx x)
+{
+  if (GET_CODE (x) == SYMBOL_REF && ! (flag_pic > 1) && SYMBOL_REF_FLAG (x))
+    return 1;
+  return legitimate_constant_p (x);
+}
+
+int
+legitimate_constant_p (rtx x)
+{
+  if (flag_pic)
+    { 
+      if (GET_CODE (x) == CONST ||
+	  GET_CODE (x) == LABEL_REF ||
+	  GET_CODE (x) == SYMBOL_REF)
+	return 1;
+    }
+  if (GET_CODE (x) == CONST_DOUBLE ||
+      GET_CODE (x) == CONST ||
+      GET_CODE (x) == LABEL_REF ||
+      GET_CODE (x) == SYMBOL_REF ||
+      (GET_CODE (x) == CONST_INT &&
+       (INTVAL (x) < -32768 || INTVAL (x) > 32767)))
+    return 0;
+  return 1;
+}



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]