s390-protos.h (s390_emit_epilogue): Parameter added.
authorAndreas Krebbel <krebbel1@de.ibm.com>
Fri, 30 Apr 2004 16:40:22 +0000 (16:40 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Fri, 30 Apr 2004 16:40:22 +0000 (16:40 +0000)
2004-04-29  Andreas Krebbel  <krebbel1@de.ibm.com>

ChangeLog:

* config/s390/s390-protos.h (s390_emit_epilogue): Parameter added.
(s390_emit_call): New function prototype added.
(s390_tls_get_offset): Function removed.
* config/s390/s390.c (s390_function_ok_for_sibcall,
s390_call_saved_register_used_p): New functions.
(TARGET_FUNCTION_OK_FOR_SIBCALL): Definition of target macro added.
(s390_tls_get_offset): Function merged into s390_emit_tls_call_insn.
(s390_emit_tls_call_insn): New function.
(legitimize_tls_address): Call s390_emit_tls_call_insn instead of
emit_call_insn.
(s390_emit_prologue): Use s390_emit_call instead of emit_call_insn.
(s390_emit_epilogue): Like s390_emit_prologue. Parameter for sibcalls
added.
* config/s390/s390.h (SIBCALL_REGNUM): New macro representing the
register number used to hold the target address for sibcalls.
* config/s390/s390.md ("sibcall", "sibcall_value", "sibcall_epilogue"):
New expanders.
("*sibcall_br", "*sibcall_brc", "*sibcall_brcl", "*sibcall_value_br",
"*sibcall_value_brc", "*sibcall_value_brcl"): New insns.
("call_exp", "call_value_exp", "call_value_tls", "call_value_tls_exp"):
Expanders removed.
("call", "call_value"): Call s390_emit_call to emit the call patterns.
("*bras", "*brasl", "*bras_r", "*brasl_r", "*bras_tls", "*brasl_tls",
"*basr", "*basr_r", "*basr_tls"): Added constraint: !SIBLING_CALL_P.
("epilogue"): Changed the call to s390_emit_epilogue to use the
new parameter.

testsuite/ChangeLog:

* gcc.dg/sibcall-3.c: Delete s390 from expected fail list.
* gcc.dg/sibcall-4.c: Likewise.
* gcc.dg/sibcall-6.c: Enable s390 as test platform.

From-SVN: r81347

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/config/s390/s390.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/sibcall-3.c
gcc/testsuite/gcc.dg/sibcall-4.c
gcc/testsuite/gcc.dg/sibcall-6.c

index 57085d84f4f509f7ebe48348f801b0eb45c829af..4ef6b7eb4b085f3fa5a5906e91ef4a4fe9ca4486 100644 (file)
@@ -1,3 +1,32 @@
+2004-04-29  Andreas Krebbel  <krebbel1@de.ibm.com>
+
+       * config/s390/s390-protos.h (s390_emit_epilogue): Parameter added.
+       (s390_emit_call): New function prototype added.
+       (s390_tls_get_offset): Function removed.
+       * config/s390/s390.c (s390_function_ok_for_sibcall,
+       s390_call_saved_register_used_p): New functions.
+       (TARGET_FUNCTION_OK_FOR_SIBCALL): Definition of target macro added.
+       (s390_tls_get_offset): Function merged into s390_emit_tls_call_insn.
+       (s390_emit_tls_call_insn): New function.
+       (legitimize_tls_address): Call s390_emit_tls_call_insn instead of
+       emit_call_insn.
+       (s390_emit_prologue): Use s390_emit_call instead of emit_call_insn.
+       (s390_emit_epilogue): Like s390_emit_prologue. Parameter for sibcalls 
+       added.
+       * config/s390/s390.h (SIBCALL_REGNUM): New macro representing the 
+       register number used to hold the target address for sibcalls.
+       * config/s390/s390.md ("sibcall", "sibcall_value", "sibcall_epilogue"):
+       New expanders.
+       ("*sibcall_br", "*sibcall_brc", "*sibcall_brcl", "*sibcall_value_br", 
+       "*sibcall_value_brc", "*sibcall_value_brcl"): New insns.
+       ("call_exp", "call_value_exp", "call_value_tls", "call_value_tls_exp"): 
+       Expanders removed.
+       ("call", "call_value"): Call s390_emit_call to emit the call patterns.
+       ("*bras", "*brasl", "*bras_r", "*brasl_r", "*bras_tls", "*brasl_tls", 
+       "*basr", "*basr_r", "*basr_tls"): Added constraint: !SIBLING_CALL_P.
+       ("epilogue"): Changed the call to s390_emit_epilogue to use the
+       new parameter.
+
 2004-04-30  Kazu Hirata  <kazu@cs.umass.edu>
 
        * bb-reorder.c, c-opts.c, cfglayout.c, cgraph.c, cgraphunit.c,
index 49dad24b5e701a3f713d2e993964c5fed539c6cd..a42dd20ab33638e465d85c38c6d0504b5d04b7c6 100644 (file)
@@ -26,7 +26,7 @@ extern void override_options (void);
 extern HOST_WIDE_INT s390_arg_frame_offset (void);
 extern void s390_load_got (int);
 extern void s390_emit_prologue (void);
-extern void s390_emit_epilogue (void);
+extern void s390_emit_epilogue (bool);
 extern void s390_function_profiler (FILE *, int);
 
 #ifdef RTX_CODE
@@ -53,7 +53,6 @@ extern int s390_alc_comparison (rtx op, enum machine_mode mode);
 extern int s390_slb_comparison (rtx op, enum machine_mode mode);
 extern int symbolic_reference_mentioned_p (rtx);
 extern int tls_symbolic_reference_mentioned_p (rtx);
-extern rtx s390_tls_get_offset (void);
 extern int legitimate_la_operand_p (rtx);
 extern int preferred_la_operand_p (rtx);
 extern int legitimate_pic_operand_p (rtx);
@@ -77,6 +76,7 @@ extern void s390_expand_movstr (rtx, rtx, rtx);
 extern void s390_expand_clrstr (rtx, rtx);
 extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx);
 extern rtx s390_return_addr_rtx (int, rtx);
+extern rtx s390_emit_call (rtx, rtx, rtx, rtx);
 
 extern bool s390_output_addr_const_extra (FILE*, rtx);
 extern void print_operand_address (FILE *, rtx);
index ed277ad4e85a08ce321ff2b49f7c3a32efd2f1b0..35dca944d77cdfce0b214b551f7613ac3f3241b6 100644 (file)
@@ -78,6 +78,8 @@ static int s390_address_cost (rtx);
 static void s390_reorg (void);
 static bool s390_valid_pointer_mode (enum machine_mode);
 static tree s390_build_builtin_va_list (void);
+static bool s390_function_ok_for_sibcall (tree, tree);
+static bool s390_call_saved_register_used (tree);
 
 #undef  TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
@@ -151,6 +153,9 @@ static tree s390_build_builtin_va_list (void);
 #undef TARGET_PROMOTE_FUNCTION_RETURN
 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
 
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 extern int reload_completed;
@@ -2610,16 +2615,29 @@ get_thread_pointer (void)
   return tp;
 }
 
-/* Construct the SYMBOL_REF for the tls_get_offset function.  */
+/* Emit a tls call insn. The call target is the SYMBOL_REF stored
+   in s390_tls_symbol which always refers to __tls_get_offset.
+   The returned offset is written to RESULT_REG and an USE rtx is
+   generated for TLS_CALL.  */
 
 static GTY(()) rtx s390_tls_symbol;
-rtx
-s390_tls_get_offset (void)
+
+static void
+s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
 {
+  rtx insn;
+  
+  if (!flag_pic)
+    abort ();
+
   if (!s390_tls_symbol)
     s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
 
-  return s390_tls_symbol;
+  insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg, 
+                        gen_rtx_REG (Pmode, RETURN_REGNUM)); 
+
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg);
+  CONST_OR_PURE_CALL_P (insn) = 1;
 }
 
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
@@ -2640,7 +2658,7 @@ legitimize_tls_address (rtx addr, rtx reg)
        new = gen_rtx_CONST (Pmode, tls_call);
        new = force_const_mem (Pmode, new);
        emit_move_insn (r2, new);
-       emit_call_insn (gen_call_value_tls (r2, tls_call));
+       s390_emit_tls_call_insn (r2, tls_call);
        insn = get_insns ();
        end_sequence ();
 
@@ -2663,7 +2681,7 @@ legitimize_tls_address (rtx addr, rtx reg)
        new = gen_rtx_CONST (Pmode, tls_call);
        new = force_const_mem (Pmode, new);
        emit_move_insn (r2, new);
-       emit_call_insn (gen_call_value_tls (r2, tls_call));
+       s390_emit_tls_call_insn (r2, tls_call);
        insn = get_insns ();
        end_sequence ();
 
@@ -5668,15 +5686,8 @@ s390_emit_prologue (void)
         algorithms located at the branch target.
 
         This must use register 1.  */
-      rtx addr;
-      rtx unkn;
-      rtx link;
-
-      addr = GEN_INT (0xfe0);
-      unkn = CONST0_RTX (SImode);
-      link = gen_rtx_REG (Pmode, 1);
-
-      emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
+      s390_emit_call (GEN_INT (0xfe0), NULL_RTX, NULL_RTX, 
+                     gen_rtx_REG (Pmode, 1));
 
       /* Emit a blockage here so that all code
         lies between the profiling mechanisms.  */
@@ -5687,7 +5698,7 @@ s390_emit_prologue (void)
 /* Expand the epilogue into a bunch of separate insns.  */
 
 void
-s390_emit_epilogue (void)
+s390_emit_epilogue (bool sibcall)
 {
   rtx frame_pointer, return_reg;
   int area_bottom, area_top, offset = 0;
@@ -5703,19 +5714,12 @@ s390_emit_epilogue (void)
 
         This must use register 1.  */
 
-      rtx addr;
-      rtx unkn;
-      rtx link;
-
-      addr = GEN_INT (0xfe6);
-      unkn = CONST0_RTX (SImode);
-      link = gen_rtx_REG (Pmode, 1);
-
       /* Emit a blockage here so that all code
          lies between the profiling mechanisms.  */
       emit_insn (gen_blockage ());
 
-      emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
+      s390_emit_call (GEN_INT (0xfe6), NULL_RTX, NULL_RTX, 
+                     gen_rtx_REG (Pmode, 1));
     }
 
   /* Check whether to use frame or stack pointer for restore.  */
@@ -5847,23 +5851,26 @@ s390_emit_epilogue (void)
            }
        }
 
-      /* Fetch return address from stack before load multiple,
-        this will do good for scheduling.  */
-
-      if (cfun->machine->save_return_addr_p
-         || (cfun->machine->first_restore_gpr < BASE_REGISTER
-             && cfun->machine->last_save_gpr > RETURN_REGNUM))
+      if (! sibcall)
        {
-         int return_regnum = find_unused_clobbered_reg();
-         if (!return_regnum)
-           return_regnum = 4;
-         return_reg = gen_rtx_REG (Pmode, return_regnum);
-
-         addr = plus_constant (frame_pointer,
-                               offset + RETURN_REGNUM * UNITS_PER_WORD);
-         addr = gen_rtx_MEM (Pmode, addr);
-         set_mem_alias_set (addr, s390_sr_alias_set);
-         emit_move_insn (return_reg, addr);
+         /* Fetch return address from stack before load multiple,
+            this will do good for scheduling.  */
+         
+         if (cfun->machine->save_return_addr_p
+             || (cfun->machine->first_restore_gpr < BASE_REGISTER
+                 && cfun->machine->last_save_gpr > RETURN_REGNUM))
+           {
+             int return_regnum = find_unused_clobbered_reg();
+             if (!return_regnum)
+               return_regnum = 4;
+             return_reg = gen_rtx_REG (Pmode, return_regnum);
+             
+             addr = plus_constant (frame_pointer,
+                                   offset + RETURN_REGNUM * UNITS_PER_WORD);
+             addr = gen_rtx_MEM (Pmode, addr);
+             set_mem_alias_set (addr, s390_sr_alias_set);
+             emit_move_insn (return_reg, addr);
+           }
        }
 
       /* ??? As references to the base register are not made
@@ -5878,13 +5885,17 @@ s390_emit_epilogue (void)
       emit_insn (insn);
     }
 
-  /* Return to caller.  */
-
-  p = rtvec_alloc (2);
+  if (! sibcall)
+    {
 
-  RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
-  RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
-  emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      /* Return to caller.  */
+      
+      p = rtvec_alloc (2);
+      
+      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
+      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
+      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+    }
 }
 
 
@@ -6999,4 +7010,179 @@ s390_init_machine_status (void)
   return ggc_alloc_cleared (sizeof (struct machine_function));
 }
 
+/* Checks whether the given ARGUMENT_LIST would use a caller
+   saved register.  This is used to decide whether sibling call
+   optimization could be performed on the respective function
+   call.  */
+
+static bool
+s390_call_saved_register_used (tree argument_list)
+{
+  CUMULATIVE_ARGS cum;
+  tree parameter;
+  enum machine_mode mode;
+  tree type;
+  rtx parm_rtx;
+  int reg;
+
+  INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0);
+
+  while (argument_list)
+    {
+      parameter = TREE_VALUE (argument_list);
+      argument_list = TREE_CHAIN (argument_list);
+
+      if (!parameter)
+       abort();
+
+      /* For an undeclared variable passed as parameter we will get
+        an ERROR_MARK node here.  */
+      if (TREE_CODE (parameter) == ERROR_MARK)
+       return true;
+
+      if (! (type = TREE_TYPE (parameter)))
+       abort();
+      
+      if (! (mode = TYPE_MODE (TREE_TYPE (parameter))))
+       abort();
+
+      if (s390_function_arg_pass_by_reference (mode, type))
+       {
+         mode = Pmode;
+         type = build_pointer_type (type);
+       }
+      
+       parm_rtx = s390_function_arg (&cum, mode, type, 0);
+
+       s390_function_arg_advance (&cum, mode, type, 0);
+       if (parm_rtx && REG_P (parm_rtx))
+        {
+          for (reg = 0;
+               reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx)); 
+               reg++)
+            if (! call_used_regs[reg + REGNO (parm_rtx)])
+              return true;
+        }
+    }
+  return false;
+}
+
+/* Return true if the given call expression can be 
+   turned into a sibling call.  
+   DECL holds the declaration of the function to be called whereas
+   EXP is the call expression itself.  */
+   
+static bool
+s390_function_ok_for_sibcall (tree decl, tree exp)
+{
+  /* The TPF epilogue uses register 1.  */
+  if (TARGET_TPF)
+    return false;
+
+  /* The 31 bit PLT code uses register 12 (GOT pointer - caller saved) 
+     which would have to be restored before the sibcall.  */
+  if (!TARGET_64BIT && flag_pic && decl && TREE_PUBLIC (decl))
+    return false;
+
+  /* Register 6 on s390 is available as an argument register but unfortunately
+     "caller saved". This makes functions needing this register for arguments
+     not suitable for sibcalls.  */ 
+  if (TREE_OPERAND (exp, 1)
+      && s390_call_saved_register_used (TREE_OPERAND (exp, 1)))
+      return false;
+
+  return true;
+}
+
+/* This function is used by the call expanders of the machine description. 
+   It emits the call insn itself together with the necessary operations 
+   to adjust the target address and returns the emitted insn.
+   ADDR_LOCATION is the target address rtx
+   TLS_CALL the location of the thread-local symbol
+   RESULT_REG the register where the result of the call should be stored
+   RETADDR_REG the register where the return address should be stored
+               If this parameter is NULL_RTX the call is considered
+               to be a sibling call.  */
+
+rtx
+s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg, 
+               rtx retaddr_reg)
+{
+  bool plt_call = false;
+  rtx insn;
+  rtx call;
+  rtx clobber;
+  rtvec vec;
+
+  /* Direct function calls need special treatment.  */
+  if (GET_CODE (addr_location) == SYMBOL_REF)
+    {
+      /* When calling a global routine in PIC mode, we must
+         replace the symbol itself with the PLT stub.  */
+      if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location))
+        {
+         addr_location = gen_rtx_UNSPEC (Pmode, 
+                                         gen_rtvec (1, addr_location), 
+                                         UNSPEC_PLT);
+         addr_location = gen_rtx_CONST (Pmode, addr_location);
+         plt_call = true;
+        }
+      
+      /* Unless we can use the bras(l) insn, force the
+         routine address into a register.  */
+      if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
+        {
+         if (flag_pic)
+           addr_location = legitimize_pic_address (addr_location, 0);
+         else
+           addr_location = force_reg (Pmode, addr_location);
+       }
+    } 
+
+  /* If it is already an indirect call or the code above moved the
+     SYMBOL_REF to somewhere else make sure the address can be found in 
+     register 1.  */
+  if (retaddr_reg == NULL_RTX
+      && GET_CODE (addr_location) != SYMBOL_REF
+      && !plt_call)
+    {
+      emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location);
+      addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM);
+    }
+  
+  addr_location = gen_rtx_MEM (QImode, addr_location);
+  call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx);
+
+  if (result_reg != NULL_RTX)
+    call = gen_rtx_SET (VOIDmode, result_reg, call);
+    
+  if (retaddr_reg != NULL_RTX)
+    {
+      clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg);
+
+      if (tls_call != NULL_RTX)
+       vec = gen_rtvec (3, call, clobber, 
+                        gen_rtx_USE (VOIDmode, tls_call));
+      else
+       vec = gen_rtvec (2, call, clobber);
+
+      call = gen_rtx_PARALLEL (VOIDmode, vec);
+    }
+
+  insn = emit_call_insn (call);
+  /* 31-bit PLT stubs and tls calls use the GOT register implicitly.  */
+  if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX)
+    {
+      /* s390_function_ok_for_sibcall should 
+        have denied sibcalls in this case.  */
+      if (retaddr_reg == NULL_RTX)
+       abort ();
+      
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+    }
+  return insn;
+}
+
 #include "gt-s390.h"
index 3354f45beedccd84853a755dffae0a5a6175899a..0c4f2b381b099f788457723f781f1662c943f8e1 100644 (file)
@@ -299,6 +299,7 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
 #define CC_REG_P(X)            (REG_P (X) && CC_REGNO_P (REGNO (X)))
 #define FRAME_REG_P(X)         (REG_P (X) && FRAME_REGNO_P (REGNO (X)))
 
+#define SIBCALL_REGNUM 1
 #define BASE_REGISTER 13
 #define RETURN_REGNUM 14
 #define CC_REGNUM 33
index f6aeefbc175d26d6c82398d89ef915c5b558d298..30a7b8d7329ff179c8b3258ff6cc67ed7720ceec 100644 (file)
   [(set_attr "type"    "none")
    (set_attr "length"  "0")])
 
-
-
 ;
-; call instruction pattern(s).
+; sibcall patterns
 ;
 
-(define_expand "call"
+(define_expand "sibcall"
   [(call (match_operand 0 "" "")
-         (match_operand 1 "" ""))
-   (use (match_operand 2 "" ""))]
+        (match_operand 1 "" ""))]
   ""
 {
-  bool plt_call = false;
-  rtx insn;
-
-  /* Direct function calls need special treatment.  */
-  if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
-    {
-      rtx sym = XEXP (operands[0], 0);
+  s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, NULL_RTX);
+  DONE;
+})
 
-      /* When calling a global routine in PIC mode, we must
-         replace the symbol itself with the PLT stub.  */
-      if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
-        {
-          sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
-          sym = gen_rtx_CONST (Pmode, sym);
-         plt_call = true;
-        }
+(define_insn "*sibcall_br"
+  [(call (mem:QI (reg 1))
+         (match_operand 0 "const_int_operand" "n"))]
+  "SIBLING_CALL_P (insn) 
+   && GET_MODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == Pmode"
+  "br\t%%r1"
+  [(set_attr "op_type" "RR")
+   (set_attr "type"  "branch")
+   (set_attr "atype" "agen")])
 
-      /* Unless we can use the bras(l) insn, force the
-         routine address into a register.  */
-      if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
-       {
-         if (flag_pic)
-           sym = legitimize_pic_address (sym, 0);
-         else
-           sym = force_reg (Pmode, sym);
-       }
+(define_insn "*sibcall_brc"
+  [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
+         (match_operand 1 "const_int_operand" "n"))]
+  "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
+  "j\t%0"
+  [(set_attr "op_type" "RI")
+   (set_attr "type"    "branch")])
 
-      operands[0] = gen_rtx_MEM (QImode, sym);
-    }
+(define_insn "*sibcall_brcl"
+  [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
+         (match_operand 1 "const_int_operand" "n"))]
+  "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH"
+  "jg\t%0"
+  [(set_attr "op_type" "RIL")
+   (set_attr "type"    "branch")])
 
-  /* Emit insn.  */
-  insn = emit_call_insn (gen_call_exp (operands[0], operands[1],
-                                      gen_rtx_REG (Pmode, RETURN_REGNUM)));
+;
+; sibcall_value patterns
+;
 
-  /* 31-bit PLT stubs use the GOT register implicitly.  */
-  if (!TARGET_64BIT && plt_call)
-    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-  
+(define_expand "sibcall_value"
+  [(set (match_operand 0 "" "")
+       (call (match_operand 1 "" "")
+             (match_operand 2 "" "")))]
+  ""
+{
+  s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], NULL_RTX);
   DONE;
 })
 
-(define_expand "call_exp"
-  [(parallel [(call (match_operand 0 "" "")
-                    (match_operand 1 "" ""))
-              (clobber (match_operand 2 "" ""))])]
+(define_insn "*sibcall_value_br"
+  [(set (match_operand 0 "" "")
+       (call (mem:QI (reg 1))
+             (match_operand 1 "const_int_operand" "n")))]
+  "SIBLING_CALL_P (insn) 
+   && GET_MODE (XEXP (XEXP (XEXP (PATTERN (insn), 1), 0), 0)) == Pmode"
+  "br\t%%r1"
+  [(set_attr "op_type" "RR")
+   (set_attr "type"  "branch")
+   (set_attr "atype" "agen")])
+
+(define_insn "*sibcall_value_brc"
+  [(set (match_operand 0 "" "")
+       (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
+             (match_operand 2 "const_int_operand" "n")))]
+  "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
+  "j\t%1"
+  [(set_attr "op_type" "RI")
+   (set_attr "type"    "branch")])
+
+(define_insn "*sibcall_value_brcl"
+  [(set (match_operand 0 "" "")
+       (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
+             (match_operand 2 "const_int_operand" "n")))]
+  "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH"
+  "jg\t%1"
+  [(set_attr "op_type" "RIL")
+   (set_attr "type"    "branch")])
+
+
+;
+; call instruction pattern(s).
+;
+
+(define_expand "call"
+  [(call (match_operand 0 "" "")
+         (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))]
   ""
-  "")
+{
+  s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, 
+                 gen_rtx_REG (Pmode, RETURN_REGNUM));
+  DONE;
+})
 
 (define_insn "*bras"
   [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
          (match_operand 1 "const_int_operand" "n"))
    (clobber (match_operand 2 "register_operand" "=r"))]
-  "TARGET_SMALL_EXEC && GET_MODE (operands[2]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_SMALL_EXEC 
+   && GET_MODE (operands[2]) == Pmode"
   "bras\t%2,%0"
   [(set_attr "op_type" "RI")
    (set_attr "type"    "jsr")])
   [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
          (match_operand 1 "const_int_operand" "n"))
    (clobber (match_operand 2 "register_operand" "=r"))]
-  "TARGET_CPU_ZARCH && GET_MODE (operands[2]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_CPU_ZARCH 
+   && GET_MODE (operands[2]) == Pmode"
   "brasl\t%2,%0"
   [(set_attr "op_type" "RIL")
    (set_attr "type"    "jsr")])
   [(call (mem:QI (match_operand 0 "address_operand" "U"))
          (match_operand 1 "const_int_operand" "n"))
    (clobber (match_operand 2 "register_operand" "=r"))]
-  "GET_MODE (operands[2]) == Pmode"
+  "!SIBLING_CALL_P (insn) && GET_MODE (operands[2]) == Pmode"
 {
   if (get_attr_op_type (insn) == OP_TYPE_RR)
     return "basr\t%2,%0";
    (use (match_operand 3 "" ""))]
   ""
 {
-  bool plt_call = false;
-  rtx insn;
-
-  /* Direct function calls need special treatment.  */
-  if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
-    {
-      rtx sym = XEXP (operands[1], 0);
-
-      /* When calling a global routine in PIC mode, we must
-         replace the symbol itself with the PLT stub.  */
-      if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
-        {
-          sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
-          sym = gen_rtx_CONST (Pmode, sym);
-         plt_call = true;
-        }
-
-      /* Unless we can use the bras(l) insn, force the
-         routine address into a register.  */
-      if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
-        {
-         if (flag_pic)
-           sym = legitimize_pic_address (sym, 0);
-         else
-           sym = force_reg (Pmode, sym);
-        }
-
-      operands[1] = gen_rtx_MEM (QImode, sym);
-    }
-
-  /* Emit insn.  */
-  insn = emit_call_insn (
-           gen_call_value_exp (operands[0], operands[1], operands[2],
-                               gen_rtx_REG (Pmode, RETURN_REGNUM)));
-
-  /* 31-bit PLT stubs use the GOT register implicitly.  */
-  if (!TARGET_64BIT && plt_call)
-    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-  
+  s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], 
+                 gen_rtx_REG (Pmode, RETURN_REGNUM));
   DONE;
 })
 
-(define_expand "call_value_exp"
-  [(parallel [(set (match_operand 0 "" "")
-                   (call (match_operand 1 "" "")
-                         (match_operand 2 "" "")))
-              (clobber (match_operand 3 "" ""))])]
-  ""
-  "")
-
 (define_insn "*bras_r"
   [(set (match_operand 0 "" "")
         (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
               (match_operand:SI 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))]
-  "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_SMALL_EXEC 
+   && GET_MODE (operands[3]) == Pmode"
   "bras\t%3,%1"
   [(set_attr "op_type" "RI")
    (set_attr "type"    "jsr")])
         (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
               (match_operand 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))]
-  "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_CPU_ZARCH 
+   && GET_MODE (operands[3]) == Pmode"
   "brasl\t%3,%1"
   [(set_attr "op_type" "RIL")
    (set_attr "type"    "jsr")])
         (call (mem:QI (match_operand 1 "address_operand" "U"))
               (match_operand 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))]
-  "GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
 {
   if (get_attr_op_type (insn) == OP_TYPE_RR)
     return "basr\t%3,%1";
    ly\t%0,%1%J2"
   [(set_attr "op_type" "RX,RXY")])
 
-(define_expand "call_value_tls"
-  [(set (match_operand 0 "" "")
-        (call (const_int 0) (const_int 0)))
-   (use (match_operand 1 "" ""))]
-  ""
-{
-  rtx insn, sym;
-
-  if (!flag_pic)
-    abort ();
-
-  sym = s390_tls_get_offset ();
-  sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
-  sym = gen_rtx_CONST (Pmode, sym);
-
-  /* Unless we can use the bras(l) insn, force the
-     routine address into a register.  */
-  if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
-    {
-      if (flag_pic)
-       sym = legitimize_pic_address (sym, 0);
-      else
-       sym = force_reg (Pmode, sym);
-    }
-
-  sym = gen_rtx_MEM (QImode, sym);
-
-  /* Emit insn.  */
-  insn = emit_call_insn (
-           gen_call_value_tls_exp (operands[0], sym, const0_rtx,
-                                   gen_rtx_REG (Pmode, RETURN_REGNUM),
-                                   operands[1]));
-
-  /* The calling convention of __tls_get_offset uses the
-     GOT register implicitly.  */
-  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), operands[0]);
-  CONST_OR_PURE_CALL_P (insn) = 1;
-
-  DONE;
-})
-
-(define_expand "call_value_tls_exp"
-  [(parallel [(set (match_operand 0 "" "")
-                   (call (match_operand 1 "" "")
-                         (match_operand 2 "" "")))
-              (clobber (match_operand 3 "" ""))
-             (use (match_operand 4 "" ""))])]
-  ""
-  "")
-
 (define_insn "*bras_tls"
   [(set (match_operand 0 "" "")
         (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
               (match_operand 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))
    (use (match_operand 4 "" ""))]
-  "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_SMALL_EXEC 
+   && GET_MODE (operands[3]) == Pmode"
   "bras\t%3,%1%J4"
   [(set_attr "op_type" "RI")
    (set_attr "type"    "jsr")])
               (match_operand 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))
    (use (match_operand 4 "" ""))]
-  "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) 
+   && TARGET_CPU_ZARCH 
+   && GET_MODE (operands[3]) == Pmode"
   "brasl\t%3,%1%J4"
   [(set_attr "op_type" "RIL")
    (set_attr "type"    "jsr")])
               (match_operand 2 "const_int_operand" "n")))
    (clobber (match_operand 3 "register_operand" "=r"))
    (use (match_operand 4 "" ""))]
-  "GET_MODE (operands[3]) == Pmode"
+  "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
 {
   if (get_attr_op_type (insn) == OP_TYPE_RR)
     return "basr\t%3,%1%J4";
 (define_expand "epilogue"
   [(use (const_int 1))]
   ""
-  "s390_emit_epilogue (); DONE;")
+  "s390_emit_epilogue (false); DONE;")
+
+(define_expand "sibcall_epilogue"
+  [(use (const_int 0))]
+  ""
+  "s390_emit_epilogue (true); DONE;")
 
 (define_insn "*return"
   [(return)
index 5cc6e2e428988e3f3622d4674b297d3e0f6b45b1..6b13596625c12842e453a845f0bbb434a0a8a1fa 100644 (file)
@@ -1,3 +1,9 @@
+2004-04-29  Andreas Krebbel  <krebbel1@de.ibm.com>
+
+       * gcc.dg/sibcall-3.c: Delete s390 from expected fail list.
+       * gcc.dg/sibcall-4.c: Likewise.
+       * gcc.dg/sibcall-6.c: Enable s390 as test platform.
+
 2004-04-30  Kazu Hirata  <kazu@cs.umass.edu>
 
        * gcc.c-torture/execute/20040331-1.c: Don't use too wide a
index d0908a2289c91095fc9f7203b2c476f34f8739af..e61110f0c41b1aef87972f430095b8039a057b66 100644 (file)
@@ -5,7 +5,7 @@
    Copyright (C) 2002 Free Software Foundation Inc.
    Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
 
-/* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* s390*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
+/* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
 /* { dg-options "-O2 -foptimize-sibling-calls" } */
 
 /* The option -foptimize-sibling-calls is the default, but serves as
index 3980879536cde651c62794b730678afd4203d451..9674e75bd9c0c9ab7be129b68625fb5014b34276 100644 (file)
@@ -5,7 +5,7 @@
    Copyright (C) 2002 Free Software Foundation Inc.
    Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
 
-/* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* s390*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
+/* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
 /* { dg-options "-O2 -foptimize-sibling-calls" } */
 
 /* The option -foptimize-sibling-calls is the default, but serves as
index 771a14e8b567258ffec7a7b635a525275b2dfccc..4b0d299f5b784f5060471812c7fb3a658ce68536 100644 (file)
@@ -6,7 +6,7 @@
    Copyright (C) 2002 Free Software Foundation Inc.
    Contributed by Andreas Bauer <baueran@in.tum.de>  */
 
-/* { dg-do run { target i?86-*-* x86_64-*-*} } */
+/* { dg-do run { target i?86-*-* s390*-*-* x86_64-*-*} } */
 /* { dg-options "-O2 -foptimize-sibling-calls" } */
 
 int foo (int);