frv-protos.h (frv_expand_epilogue, [...]): Add bool argument.
authorAlexandre Oliva <aoliva@redhat.com>
Sun, 2 May 2004 04:57:47 +0000 (04:57 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Sun, 2 May 2004 04:57:47 +0000 (04:57 +0000)
* config/frv/frv-protos.h (frv_expand_epilogue,
frv_expand_fdpic_call): Add bool argument.
* config/frv/frv.c (frv_function_ok_for_sibcall): New.
(TARGET_FUNCTION_OK_FOR_SIBCALL): Define to it.
(frv_expand_epilogue): Use new argument to decide whether to emit
return instruction or copy the return address to LR.
(frv_expand_fdpic_call): Inline PLT entry when emitting direct
sibcalls.
(sibcall_operand): New.
* config/frv/frv.h (PREDICATE_CODES): call_operand doesn't match
PLUS nor LABEL_REF.  Add sibcall_operand.
* config/frv/frv.md (call, call_value): Pass false to
frv_expand_fdpic_call.
(call_fdpicdi, call_value_fdpicdi): Insert %i0 in calll.
(sibcall, sibcall_internal, sibcall_fdpicdi, sibcall_value,
sibcall_value_internal, sibcall_value_fdpicdi): New.
(return_unsigned_true, return_unsigned_false): New.
(epilogue): Adjust call to frv_expand_epilogue.
(sibcall_epilogue): New.

From-SVN: r81405

gcc/ChangeLog
gcc/config/frv/frv-protos.h
gcc/config/frv/frv.c
gcc/config/frv/frv.h
gcc/config/frv/frv.md

index c2373755047487c6d11ce5c38623284bfc96ba92..fb929086eed28a0baf520958ed10fadf30eeb4bf 100644 (file)
@@ -1,5 +1,25 @@
 2004-05-02  Alexandre Oliva  <aoliva@redhat.com>
 
+       * config/frv/frv-protos.h (frv_expand_epilogue,
+       frv_expand_fdpic_call): Add bool argument.
+       * config/frv/frv.c (frv_function_ok_for_sibcall): New.
+       (TARGET_FUNCTION_OK_FOR_SIBCALL): Define to it.
+       (frv_expand_epilogue): Use new argument to decide whether to emit
+       return instruction or copy the return address to LR.
+       (frv_expand_fdpic_call): Inline PLT entry when emitting direct
+       sibcalls.
+       (sibcall_operand): New.
+       * config/frv/frv.h (PREDICATE_CODES): call_operand doesn't match
+       PLUS nor LABEL_REF.  Add sibcall_operand.
+       * config/frv/frv.md (call, call_value): Pass false to
+       frv_expand_fdpic_call.
+       (call_fdpicdi, call_value_fdpicdi): Insert %i0 in calll.
+       (sibcall, sibcall_internal, sibcall_fdpicdi, sibcall_value,
+       sibcall_value_internal, sibcall_value_fdpicdi): New.
+       (return_unsigned_true, return_unsigned_false): New.
+       (epilogue): Adjust call to frv_expand_epilogue.
+       (sibcall_epilogue): New.
+
        * config/frv/frv.h (ASM_SPEC): Pass -mno-fdpic as -mnopic.
        (CPP_SPEC, CPP_SIMPLE_SPEC): Undefine __FRV_ACC__ and __FRV_FPR__
        before redefining them.
index 642635090d03c180728d6c95dcb95d97de838bc4..3a0e386d25d0cf71848fd1455963720cf61edac6 100644 (file)
@@ -53,7 +53,7 @@ extern frv_cpu_t frv_cpu_type;                        /* value of -mcpu= */
 
 /* Define functions defined in frv.c */
 extern void frv_expand_prologue                        (void);
-extern void frv_expand_epilogue                        (int);
+extern void frv_expand_epilogue                        (bool);
 extern void frv_override_options               (void);
 extern void frv_optimization_options           (int, int);
 extern void frv_conditional_register_usage     (void);
@@ -225,7 +225,7 @@ extern int even_acc_operand         (rtx, enum machine_mode);
 extern int quad_acc_operand            (rtx, enum machine_mode);
 extern int accg_operand                        (rtx, enum machine_mode);
 extern rtx frv_matching_accg_for_acc   (rtx);
-extern void frv_expand_fdpic_call      (rtx *, int);
+extern void frv_expand_fdpic_call      (rtx *, bool, bool);
 extern rtx frv_gen_GPsym2reg           (rtx, rtx);
 #endif
 
index d5808bfa7ac45b0f95f65e86393ceb1e6cb66ae1..92e0dd213fa5afdde9c4e30af33faa679cba6979 100644 (file)
@@ -285,6 +285,7 @@ static bool frv_cannot_force_const_mem              (rtx);
 static const char *unspec_got_name             (int);
 static void frv_output_const_unspec            (FILE *,
                                                 const struct frv_unspec *);
+static bool frv_function_ok_for_sibcall                (tree, tree);
 static rtx frv_struct_value_rtx                        (tree, int);
 \f
 /* Initialize the GCC target structure.  */
@@ -319,6 +320,8 @@ static rtx frv_struct_value_rtx                     (tree, int);
 #undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
 #define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE frv_use_dfa_pipeline_interface
 
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL frv_function_ok_for_sibcall
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
 
@@ -332,6 +335,16 @@ static rtx frv_struct_value_rtx                    (tree, int);
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Any function call that satisfies the machine-independent
+   requirements is eligible on FR-V.  */
+
+static bool
+frv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
+                            tree exp ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
 /* Return true if SYMBOL is a small data symbol and relocation RELOC
    can be used to access it directly in a load or store.  */
 
@@ -1749,7 +1762,7 @@ frv_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
    slots for arguments passed to the current function.  */
 
 void
-frv_expand_epilogue (int sibcall_p)
+frv_expand_epilogue (bool emit_return)
 {
   frv_stack_t *info = frv_stack_info ();
   rtx fp = frame_pointer_rtx;
@@ -1769,9 +1782,7 @@ frv_expand_epilogue (int sibcall_p)
 
   /* Set RETURN_ADDR to the address we should return to.  Set it to NULL if
      no return instruction should be emitted.  */
-  if (sibcall_p)
-    return_addr = 0;
-  else if (info->save_p[LR_REGNO])
+  if (info->save_p[LR_REGNO])
     {
       int lr_offset;
       rtx mem;
@@ -1814,8 +1825,20 @@ frv_expand_epilogue (int sibcall_p)
   if (current_function_calls_eh_return)
     emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX));
 
-  if (return_addr)
+  if (emit_return)
     emit_jump_insn (gen_epilogue_return (return_addr));
+  else
+    {
+      rtx lr = return_addr;
+
+      if (REGNO (return_addr) != LR_REGNO)
+       {
+         lr = gen_rtx_REG (Pmode, LR_REGNO);
+         emit_move_insn (lr, return_addr);
+       }
+
+      emit_insn (gen_rtx_USE (VOIDmode, lr));
+    }
 }
 
 \f
@@ -3529,7 +3552,7 @@ frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
 }
 
 void
-frv_expand_fdpic_call (rtx *operands, int ret_value)
+frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
 {
   rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
   rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG);
@@ -3565,8 +3588,9 @@ frv_expand_fdpic_call (rtx *operands, int ret_value)
      all external functions, so one would have to also mark function
      declarations available in the same module with non-default
      visibility, which is advantageous in itself.  */
-  if (GET_CODE (addr) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (addr)
-      && TARGET_INLINE_PLT)
+  if (GET_CODE (addr) == SYMBOL_REF
+      && ((!SYMBOL_REF_LOCAL_P (addr) && TARGET_INLINE_PLT)
+         || sibcall))
     {
       rtx x, dest;
       dest = gen_reg_rtx (SImode);
@@ -3598,7 +3622,11 @@ frv_expand_fdpic_call (rtx *operands, int ret_value)
   picreg = gen_reg_rtx (DImode);
   emit_insn (gen_movdi_ldd (picreg, addr));
 
-  if (ret_value)
+  if (sibcall && ret_value)
+    c = gen_sibcall_value_fdpicdi (rvrtx, picreg, const0_rtx);
+  else if (sibcall)
+    c = gen_sibcall_fdpicdi (picreg, const0_rtx);
+  else if (ret_value)
     c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr);
   else
     c = gen_call_fdpicdi (picreg, const0_rtx, lr);
@@ -4766,6 +4794,21 @@ call_operand (rtx op, enum machine_mode mode)
   return gpr_or_int12_operand (op, mode);
 }
 
+/* Return true if operand is a memory reference suitable for a sibcall.  */
+
+int
+sibcall_operand (rtx op, enum machine_mode mode)
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
+    return FALSE;
+
+  /* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
+     never occur anyway), but prevents reload from not handling the case
+     properly of a call through a pointer on a function that calls
+     vfork/setjmp, etc. due to the need to flush all of the registers to stack.  */
+  return gpr_or_int12_operand (op, mode);
+}
+
 /* Return true if operator is a kind of relational operator.  */
 
 int
index 438fbfef4884d65d71989942571f1f951468b581..e6baec07973661a8eb8f66b5341d1b9005c05241 100644 (file)
@@ -3111,8 +3111,10 @@ do {                                                                    \
   { "odd_fpr_operand",                 { REG, SUBREG }},               \
   { "dbl_memory_one_insn_operand",     { MEM }},                       \
   { "dbl_memory_two_insn_operand",     { MEM }},                       \
-  { "call_operand",                    { REG, SUBREG, PLUS, CONST_INT, \
-                                         SYMBOL_REF, LABEL_REF, CONST }}, \
+  { "call_operand",                    { REG, SUBREG, CONST_INT,       \
+                                         CONST, SYMBOL_REF }},         \
+  { "sibcall_operand",                 { REG, SUBREG, CONST_INT,       \
+                                         CONST }},                     \
   { "upper_int16_operand",             { CONST_INT }},                 \
   { "uint16_operand",                  { CONST_INT }},                 \
   { "relational_operator",             { EQ, NE, LE, LT, GE, GT,       \
index 20170bd412312a1bc882fb98647c568f0ea4b189..36b6d8e7afc5d25a7ca7e690e36729f478ceaa4b 100644 (file)
     operands[2] = const0_rtx;
 
   if (TARGET_FDPIC)
-    frv_expand_fdpic_call (operands, 0);
+    frv_expand_fdpic_call (operands, false, false);
   else
     emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr));
 
         (match_operand 1 "" ""))
    (clobber (match_operand:SI 2 "lr_operand" "=l"))]
   "TARGET_FDPIC"
-  "calll %M0"
+  "call%i0l %M0"
   [(set_attr "length" "4")
    (set_attr "type" "jumpl")])
 
   [(set_attr "length" "4")
    (set_attr "type" "call,jumpl")])
 
+(define_expand "sibcall"
+  [(use (match_operand:QI 0 "" ""))
+   (use (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))]
+  ""
+  "
+{
+  rtx addr;
+
+  if (GET_CODE (operands[0]) != MEM)
+    abort ();
+
+  addr = XEXP (operands[0], 0);
+  if (! sibcall_operand (addr, Pmode))
+    addr = force_reg (Pmode, addr);
+
+  if (! operands[2])
+    operands[2] = const0_rtx;
+
+  if (TARGET_FDPIC)
+    frv_expand_fdpic_call (operands, false, true);
+  else
+    emit_call_insn (gen_sibcall_internal (addr, operands[1], operands[2]));
+
+  DONE;
+}")
+  
+;; It might seem that these sibcall patterns are missing references to
+;; LR, but they're not necessary because sibcall_epilogue will make
+;; sure LR is restored, and having LR here will set
+;; regs_ever_used[REG_LR], forcing it to be saved on the stack, and
+;; then restored in sibcalls and regular return code paths, even if
+;; the function becomes a leaf function after tail-call elimination.
+
+;; We must not use a call-saved register here.  `W' limits ourselves
+;; to gr14 or gr15, but since we're almost running out of constraint
+;; letters, and most other call-clobbered registers are often used for
+;; argument-passing, this will do.
+(define_insn "sibcall_internal"
+  [(call (mem:QI (match_operand:SI 0 "sibcall_operand" "WNOP"))
+        (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (return)]
+  "! TARGET_FDPIC"
+  "jmp%i0l %M0"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl")])
+
+(define_insn "sibcall_fdpicdi"
+  [(call (mem:QI (match_operand:DI 0 "fdpic_fptr_operand" "W"))
+        (match_operand 1 "" ""))
+   (return)]
+  "TARGET_FDPIC"
+  "jmp%i0l %M0"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl")])
+
+
 ;; Subroutine call instruction returning a value.  Operand 0 is the hard
 ;; register in which the value is returned.  There are three more operands, the
 ;; same as the three operands of the `call' instruction (but with numbers
     operands[3] = const0_rtx;
 
   if (TARGET_FDPIC)
-    frv_expand_fdpic_call (operands, 1);
+    frv_expand_fdpic_call (operands, true, false);
   else
     emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
                                             operands[3], lr));
              (match_operand 2 "" "")))
    (clobber (match_operand:SI 3 "lr_operand" "=l"))]
   "TARGET_FDPIC"
-  "calll %M1"
+  "call%i1l %M1"
   [(set_attr "length" "4")
    (set_attr "type" "jumpl")])
 
   [(set_attr "length" "4")
    (set_attr "type" "call,jumpl")])
 
+(define_expand "sibcall_value"
+  [(use (match_operand 0 "" ""))
+   (use (match_operand:QI 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))
+   (use (match_operand 4 "" ""))]
+  ""
+  "
+{
+  rtx addr;
+
+  if (GET_CODE (operands[1]) != MEM)
+    abort ();
+
+  addr = XEXP (operands[1], 0);
+  if (! sibcall_operand (addr, Pmode))
+    addr = force_reg (Pmode, addr);
+
+  if (! operands[3])
+    operands[3] = const0_rtx;
+
+  if (TARGET_FDPIC)
+    frv_expand_fdpic_call (operands, true, true);
+  else
+    emit_call_insn (gen_sibcall_value_internal (operands[0], addr, operands[2],
+                                               operands[3]));
+  DONE;
+}")
+
+(define_insn "sibcall_value_internal"
+  [(set (match_operand 0 "register_operand" "=d")
+       (call (mem:QI (match_operand:SI 1 "sibcall_operand" "WNOP"))
+                     (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (return)]
+  "! TARGET_FDPIC"
+  "jmp%i1l %M1"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl")])
+
+(define_insn "sibcall_value_fdpicdi"
+  [(set (match_operand 0 "register_operand" "=d")
+       (call (mem:QI (match_operand:DI 1 "fdpic_fptr_operand" "W"))
+             (match_operand 2 "" "")))
+   (return)]
+  "TARGET_FDPIC"
+  "jmp%i1l %M1"
+  [(set_attr "length" "4")
+   (set_attr "type" "jumpl")])
+
 ;; return instruction generated instead of jmp to epilog
 (define_expand "return"
   [(parallel [(return)
   [(set_attr "length" "4")
    (set_attr "type" "jump,jumpl")])
 
+(define_insn "*return_unsigned_true"
+  [(set (pc)
+       (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator"
+                                            [(match_operand 1 "icc_operand" "t")
+                                             (const_int 0)])
+                     (return)
+                     (pc)))]
+  "direct_return_p ()"
+  "b%c0lr %1,%#"
+  [(set_attr "length" "4")
+   (set_attr "type" "jump")])
+
+(define_insn "*return_unsigned_false"
+  [(set (pc)
+       (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator"
+                                            [(match_operand 1 "icc_operand" "t")
+                                             (const_int 0)])
+                     (pc)
+                     (return)))]
+  "direct_return_p ()"
+  "b%C0lr %1,%#"
+  [(set_attr "length" "4")
+   (set_attr "type" "jump")])
+
 ;; A version of addsi3 for deallocating stack space at the end of the
 ;; epilogue.  The addition is done in parallel with an (unspec_volatile),
 ;; which represents the clobbering of the deallocated space.
   ""
   "
 {
-  frv_expand_epilogue (FALSE);
+  frv_expand_epilogue (true);
   DONE;
 }")
 
   ""
   "
 {
-  frv_expand_epilogue (TRUE);
+  frv_expand_epilogue (false);
   DONE;
 }")