Only in gcc-3.2-cvs/gcc: .#calls.c.1.2 Only in gcc-3.2-cvs/gcc: .#cfgbuild.c.1.1.1.1 Only in gcc-3.2-cvs/gcc: .#except.c.1.1.1.1 Only in gcc-3.2-cvs/gcc: .#function.c.1.1.1.1 Only in gcc-3.2-cvs/gcc: .#integrate.c.1.2 Only in gcc-3.2-cvs/gcc: .#jump.c.1.1.1.1 Only in gcc-3.2-cvs/gcc: .#rtl.h.1.2 Only in gcc-3.2-cvs/gcc: .#sibcall.c.1.1.1.1 Only in gcc-3.2-cvs/gcc: .#toplev.c.1.2 Only in gcc-3.2-cvs/gcc: CVS Only in gcc-3.2-cvs/gcc: TAGS Common subdirectories: gcc-3.2/gcc/ada and gcc-3.2-cvs/gcc/ada diff -b -w -B -d -p -c gcc-3.2/gcc/calls.c gcc-3.2-cvs/gcc/calls.c *** gcc-3.2/gcc/calls.c Fri Apr 5 09:28:47 2002 --- gcc-3.2-cvs/gcc/calls.c Mon Sep 9 11:31:10 2002 *************** static int calls_function_1 PARAMS ((tre *** 167,172 **** --- 167,173 ---- /* Nonzero if this is a syscall that makes a new process in the image of the current one. */ #define ECF_FORK_OR_EXEC 128 + /* Nonzero if this is a sib call. */ #define ECF_SIBCALL 256 /* Nonzero if this is a call to "pure" function (like const function, but may read memory. */ *************** static int calls_function_1 PARAMS ((tre *** 178,183 **** --- 179,195 ---- #define ECF_ALWAYS_RETURN 2048 /* Create libcall block around the call. */ #define ECF_LIBCALL_BLOCK 4096 + /* Nonzero if this call is a more general tail call, i.e. + (a super sib call). */ + #define ECF_TAILCALL 8192 + + /* Definitions for the different call instruction sequences + generated by expand_call. */ + enum call_seq { + sib_call_seq = 0, + normal_call_seq, + tail_call_seq + }; static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, rtx, *************** emit_call_1 (funexp, fndecl, funtype, st *** 627,633 **** current_function_calls_setjmp = 1; } ! SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ --- 639,654 ---- current_function_calls_setjmp = 1; } ! /* Annotate sib- and supersib-calls, i.e. calls in tail position. */ ! if ((ecf_flags & ECF_SIBCALL) || (ecf_flags & ECF_TAILCALL)) ! SIBLING_CALL_P (call_insn) = 1; ! ! /* This flag is important for determining in final.c, whether ! the current function is a leaf or not. */ ! if (ecf_flags & ECF_TAILCALL) ! TAIL_CALL_P (call_insn) = 1; ! else ! TAIL_CALL_P (call_insn) = 0; /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ *************** expand_call (exp, target, ignore) *** 2085,2091 **** rtx tail_recursion_insns = NULL_RTX; /* Sequence of insns to perform a normal "call". */ rtx normal_call_insns = NULL_RTX; ! /* Sequence of insns to perform a tail recursive "call". */ rtx tail_call_insns = NULL_RTX; /* Data type of the function. */ tree funtype; --- 2106,2114 ---- rtx tail_recursion_insns = NULL_RTX; /* Sequence of insns to perform a normal "call". */ rtx normal_call_insns = NULL_RTX; ! /* Sequence of insns to perform a sib call. */ ! rtx sib_call_insns = NULL_RTX; ! /* Sequence of insns to perform a tail call. */ rtx tail_call_insns = NULL_RTX; /* Data type of the function. */ tree funtype; *************** expand_call (exp, target, ignore) *** 2094,2101 **** tree fndecl = 0; rtx insn; int try_tail_call = 1; int try_tail_recursion = 1; ! int pass; /* Register in which non-BLKmode value will be returned, or 0 if no value or if value is BLKmode. */ --- 2117,2125 ---- tree fndecl = 0; rtx insn; int try_tail_call = 1; + int try_sib_call = 1; int try_tail_recursion = 1; ! int pass = 0; /* Register in which non-BLKmode value will be returned, or 0 if no value or if value is BLKmode. */ *************** expand_call (exp, target, ignore) *** 2124,2130 **** /* Vector of information about each argument. Arguments are numbered in the order they will be pushed, not the order they are written. */ ! struct arg_data *args; /* Total size in bytes of all the stack-parms scanned so far. */ struct args_size args_size; --- 2148,2154 ---- /* Vector of information about each argument. Arguments are numbered in the order they will be pushed, not the order they are written. */ ! struct arg_data *args, *args_tmp; /* Total size in bytes of all the stack-parms scanned so far. */ struct args_size args_size; *************** expand_call (exp, target, ignore) *** 2375,2380 **** --- 2399,2409 ---- args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data)); memset ((char *) args, 0, num_actuals * sizeof (struct arg_data)); + /* Make space for a copy of args, needed when iterating through the + call chain generation. */ + args_tmp = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data)); + memset ((char *) args_tmp, 0, num_actuals * sizeof (struct arg_data)); + /* Build up entries in the ARGS array, compute the size of the arguments into ARGS_SIZE, etc. */ initialize_argument_information (num_actuals, args, &args_size, *************** expand_call (exp, target, ignore) *** 2422,2433 **** This is most often true of sjlj-exceptions, which we couldn't tail-call to anyway. */ ! if (currently_expanding_call++ != 0 || !flag_optimize_sibling_calls || !rtx_equal_function_value_matters || any_pending_cleanups (1) || args_size.var) ! try_tail_call = try_tail_recursion = 0; /* Tail recursion fails, when we are not dealing with recursive calls. */ if (!try_tail_recursion --- 2451,2476 ---- This is most often true of sjlj-exceptions, which we couldn't tail-call to anyway. */ ! if (currently_expanding_call != 0 || !flag_optimize_sibling_calls || !rtx_equal_function_value_matters || any_pending_cleanups (1) || args_size.var) ! try_sib_call = try_tail_recursion = 0; ! ! /* This check is somewhat redundant, but for the sake of ! expandability and convenient editing, it makes sense ! to keep it for now. Later on, we try to cut down the ! conditions bit by bit. */ ! ! if (currently_expanding_call != 0 ! || !flag_optimize_tail_calls ! || !rtx_equal_function_value_matters ! || any_pending_cleanups (1) ! || args_size.var) ! try_tail_call = 0; ! ! currently_expanding_call++; /* Tail recursion fails, when we are not dealing with recursive calls. */ if (!try_tail_recursion *************** expand_call (exp, target, ignore) *** 2442,2448 **** #else 1 #endif - || !try_tail_call /* Doing sibling call optimization needs some work, since structure_value_addr can be allocated on the stack. It does not seem worth the effort since few optimizable --- 2485,2490 ---- *************** expand_call (exp, target, ignore) *** 2468,2476 **** != RETURN_POPS_ARGS (current_function_decl, TREE_TYPE (current_function_decl), current_function_args_size)) ! try_tail_call = 0; ! if (try_tail_call || try_tail_recursion) { int end, inc; actparms = NULL_TREE; --- 2510,2518 ---- != RETURN_POPS_ARGS (current_function_decl, TREE_TYPE (current_function_decl), current_function_args_size)) ! try_tail_call = try_sib_call = 0; ! if (try_sib_call || try_tail_recursion) { int end, inc; actparms = NULL_TREE; *************** expand_call (exp, target, ignore) *** 2536,2542 **** /* Expanding one of those dangerous arguments could have added cleanups, but otherwise give it a whirl. */ if (any_pending_cleanups (1)) ! try_tail_call = try_tail_recursion = 0; } /* Generate a tail recursion sequence when calling ourselves. */ --- 2578,2584 ---- /* Expanding one of those dangerous arguments could have added cleanups, but otherwise give it a whirl. */ if (any_pending_cleanups (1)) ! try_sib_call = try_tail_recursion = 0; } /* Generate a tail recursion sequence when calling ourselves. */ *************** expand_call (exp, target, ignore) *** 2568,2574 **** if (optimize_tail_recursion (actparms, get_last_insn ())) { if (any_pending_cleanups (1)) ! try_tail_call = try_tail_recursion = 0; else tail_recursion_insns = get_insns (); } --- 2610,2616 ---- if (optimize_tail_recursion (actparms, get_last_insn ())) { if (any_pending_cleanups (1)) ! try_sib_call = try_tail_recursion = 0; else tail_recursion_insns = get_insns (); } *************** expand_call (exp, target, ignore) *** 2606,2617 **** function_call_count++; ! /* We want to make two insn chains; one for a sibling call, the other ! for a normal call. We will select one of the two chains after ! initial RTL generation is complete. */ ! for (pass = 0; pass < 2; pass++) { int sibcall_failure = 0; /* We want to emit any pending stack adjustments before the tail recursion "call". That way we know any adjustment after the tail recursion call can be ignored if we indeed use the tail recursion --- 2648,2664 ---- function_call_count++; ! /* Save the vector which holds function arguments and ! corresponding addresses. */ ! memcpy (args_tmp, args, num_actuals * sizeof (struct arg_data)); ! ! /* We want to make three insn chains; one for a sibling call, the ! other for a normal call and the super sib call. We will select ! one of three chains after initial RTL generation is complete. */ ! for (pass = 0; pass < 3; pass++) { int sibcall_failure = 0; + int tailcall_failure = 0; /* We want to emit any pending stack adjustments before the tail recursion "call". That way we know any adjustment after the tail recursion call can be ignored if we indeed use the tail recursion *************** expand_call (exp, target, ignore) *** 2621,2644 **** rtx insns; rtx before_call, next_arg_reg; ! if (pass == 0) { - if (! try_tail_call) - continue; - /* Emit any queued insns now; otherwise they would end up in only one of the alternates. */ emit_queue (); /* State variables we need to save and restore between ! iterations. */ save_pending_stack_adjust = pending_stack_adjust; save_stack_pointer_delta = stack_pointer_delta; } ! if (pass) ! flags &= ~ECF_SIBCALL; else flags |= ECF_SIBCALL; /* Other state variables that we must reinitialize each time through the loop (that are not initialized by the loop itself). */ --- 2668,2714 ---- rtx insns; rtx before_call, next_arg_reg; ! if (pass == sib_call_seq ! && (try_tail_call || try_sib_call)) { /* Emit any queued insns now; otherwise they would end up in only one of the alternates. */ emit_queue (); + } + + if (pass == sib_call_seq) + { + if (! try_sib_call) + continue; /* State variables we need to save and restore between ! iterations; only for sibcalls and tail recursion. */ save_pending_stack_adjust = pending_stack_adjust; save_stack_pointer_delta = stack_pointer_delta; } ! ! if (pass == tail_call_seq) ! { ! if (! try_tail_call) ! continue; else + { + /* Restore arguments for reevaluation. This can surely + be done in a nicer way, but for the purpose of getting + things running, it does the job just fine. */ + memcpy (args, args_tmp, num_actuals * sizeof (struct arg_data)); + } + } + + if (pass == sib_call_seq) flags |= ECF_SIBCALL; + else + flags &= ~ECF_SIBCALL; + + if (pass == tail_call_seq) + flags |= ECF_TAILCALL; + else + flags &= ~ECF_TAILCALL; /* Other state variables that we must reinitialize each time through the loop (that are not initialized by the loop itself). */ *************** expand_call (exp, target, ignore) *** 2651,2657 **** sibcall_failure instead of continuing the loop. */ start_sequence (); ! if (pass == 0) { /* We know at this point that there are not currently any pending cleanups. If, however, in the process of evaluating --- 2721,2727 ---- sibcall_failure instead of continuing the loop. */ start_sequence (); ! if (pass == sib_call_seq) { /* We know at this point that there are not currently any pending cleanups. If, however, in the process of evaluating *************** expand_call (exp, target, ignore) *** 2668,2679 **** if (pending_stack_adjust >= 32 || (pending_stack_adjust > 0 && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED))) ! || pass == 0) do_pending_stack_adjust (); /* When calling a const function, we must pop the stack args right away, so that the pop is deleted or moved with the call. */ ! if (pass && (flags & ECF_LIBCALL_BLOCK)) NO_DEFER_POP; #ifdef FINAL_REG_PARM_STACK_SPACE --- 2738,2750 ---- if (pending_stack_adjust >= 32 || (pending_stack_adjust > 0 && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED))) ! || pass == sib_call_seq) do_pending_stack_adjust (); /* When calling a const function, we must pop the stack args right away, so that the pop is deleted or moved with the call. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) ! && (flags & ECF_LIBCALL_BLOCK)) NO_DEFER_POP; #ifdef FINAL_REG_PARM_STACK_SPACE *************** expand_call (exp, target, ignore) *** 2681,2692 **** args_size.var); #endif /* Precompute any arguments as needed. */ ! if (pass) precompute_arguments (flags, num_actuals, args); /* Now we are about to start emitting insns that can be deleted if a libcall is deleted. */ ! if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC))) start_sequence (); adjusted_args_size = args_size; --- 2752,2764 ---- args_size.var); #endif /* Precompute any arguments as needed. */ ! if (pass == normal_call_seq || pass == tail_call_seq) precompute_arguments (flags, num_actuals, args); /* Now we are about to start emitting insns that can be deleted if a libcall is deleted. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) ! && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC))) start_sequence (); adjusted_args_size = args_size; *************** expand_call (exp, target, ignore) *** 2695,2711 **** and there may be a minimum required size. When generating a sibcall pattern, do not round up, since we'll be re-using whatever space our caller provided. */ unadjusted_args_size = compute_argument_block_size (reg_parm_stack_space, &adjusted_args_size, ! (pass == 0 ? 0 : preferred_stack_boundary)); old_stack_allocated = stack_pointer_delta - pending_stack_adjust; /* The argument block when performing a sibling call is the incoming argument block. */ ! if (pass == 0) { argblock = virtual_incoming_args_rtx; stored_args_map = sbitmap_alloc (args_size.constant); --- 2767,2789 ---- and there may be a minimum required size. When generating a sibcall pattern, do not round up, since we'll be re-using whatever space our caller provided. */ + /* ??? Should this also apply to general tail calls. */ unadjusted_args_size = compute_argument_block_size (reg_parm_stack_space, &adjusted_args_size, ! (pass == sib_call_seq ? 0 : preferred_stack_boundary)); old_stack_allocated = stack_pointer_delta - pending_stack_adjust; /* The argument block when performing a sibling call is the incoming argument block. */ ! ! /* The same thing holds for general tail calls, but we'll ! shift the arguments right before we jump to the callee, ! not earlier. */ ! ! if (pass == sib_call_seq) { argblock = virtual_incoming_args_rtx; stored_args_map = sbitmap_alloc (args_size.constant); *************** expand_call (exp, target, ignore) *** 2929,2937 **** { if (pcc_struct_value) valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), ! fndecl, (pass == 0)); else ! valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0)); } /* Precompute all register parameters. It isn't safe to compute anything --- 3007,3016 ---- { if (pcc_struct_value) valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), ! fndecl, (pass == sib_call_seq)); else ! valreg = hard_function_value (TREE_TYPE (exp), fndecl, ! (pass == sib_call_seq)); } /* Precompute all register parameters. It isn't safe to compute anything *************** expand_call (exp, target, ignore) *** 2941,2947 **** #ifdef REG_PARM_STACK_SPACE /* Save the fixed argument area if it's part of the caller's frame and is clobbered by argument setup for this call. */ ! if (ACCUMULATE_OUTGOING_ARGS && pass) save_area = save_fixed_argument_area (reg_parm_stack_space, argblock, &low_to_save, &high_to_save); #endif --- 3020,3027 ---- #ifdef REG_PARM_STACK_SPACE /* Save the fixed argument area if it's part of the caller's frame and is clobbered by argument setup for this call. */ ! if (ACCUMULATE_OUTGOING_ARGS ! && (pass == normal_call_seq || pass == tail_call_seq)) save_area = save_fixed_argument_area (reg_parm_stack_space, argblock, &low_to_save, &high_to_save); #endif *************** expand_call (exp, target, ignore) *** 2960,2970 **** if (store_one_arg (&args[i], argblock, flags, adjusted_args_size.var != 0, reg_parm_stack_space) ! || (pass == 0 && check_sibcall_argument_overlap (before_arg, &args[i]))) sibcall_failure = 1; } /* If we have a parm that is passed in registers but not in memory and whose alignment does not permit a direct copy into registers, --- 3040,3054 ---- if (store_one_arg (&args[i], argblock, flags, adjusted_args_size.var != 0, reg_parm_stack_space) ! || (pass == sib_call_seq && check_sibcall_argument_overlap (before_arg, &args[i]))) + { + /* Debugging stuff; remove, if you please. */ + warning ("sib call arguments overlap"); sibcall_failure = 1; } + } /* If we have a parm that is passed in registers but not in memory and whose alignment does not permit a direct copy into registers, *************** expand_call (exp, target, ignore) *** 2984,2994 **** if (store_one_arg (&args[i], argblock, flags, adjusted_args_size.var != 0, reg_parm_stack_space) ! || (pass == 0 && check_sibcall_argument_overlap (before_arg, &args[i]))) sibcall_failure = 1; } /* If we pushed args in forward order, perform stack alignment after pushing the last arg. */ --- 3068,3082 ---- if (store_one_arg (&args[i], argblock, flags, adjusted_args_size.var != 0, reg_parm_stack_space) ! || (pass == sib_call_seq && check_sibcall_argument_overlap (before_arg, &args[i]))) + { + /* Debugging stuff; remove, if you please. */ + warning ("sib call arguments overlap"); sibcall_failure = 1; } + } /* If we pushed args in forward order, perform stack alignment after pushing the last arg. */ *************** expand_call (exp, target, ignore) *** 3007,3013 **** /* Pass the function the address in which to return a structure value. */ ! if (pass != 0 && structure_value_addr && ! structure_value_addr_parm) { emit_move_insn (struct_value_rtx, force_reg (Pmode, --- 3095,3102 ---- /* Pass the function the address in which to return a structure value. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) ! && structure_value_addr && ! structure_value_addr_parm) { emit_move_insn (struct_value_rtx, force_reg (Pmode, *************** expand_call (exp, target, ignore) *** 3019,3025 **** } funexp = prepare_call_address (funexp, fndecl, &call_fusage, ! reg_parm_seen, pass == 0); load_register_parameters (args, num_actuals, &call_fusage, flags); --- 3108,3114 ---- } funexp = prepare_call_address (funexp, fndecl, &call_fusage, ! reg_parm_seen, pass == sib_call_seq); load_register_parameters (args, num_actuals, &call_fusage, flags); *************** expand_call (exp, target, ignore) *** 3033,3039 **** /* Set up next argument register. For sibling calls on machines with register windows this should be the incoming register. */ #ifdef FUNCTION_INCOMING_ARG ! if (pass == 0) next_arg_reg = FUNCTION_INCOMING_ARG (args_so_far, VOIDmode, void_type_node, 1); else --- 3122,3128 ---- /* Set up next argument register. For sibling calls on machines with register windows this should be the incoming register. */ #ifdef FUNCTION_INCOMING_ARG ! if (pass == sib_call_seq) next_arg_reg = FUNCTION_INCOMING_ARG (args_so_far, VOIDmode, void_type_node, 1); else *************** expand_call (exp, target, ignore) *** 3045,3053 **** now! */ /* Stack must be properly aligned now. */ ! if (pass && stack_pointer_delta % preferred_unit_stack_boundary) abort (); /* Generate the actual call instruction. */ emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size, adjusted_args_size.constant, struct_value_size, --- 3134,3169 ---- now! */ /* Stack must be properly aligned now. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) ! && stack_pointer_delta % preferred_unit_stack_boundary) abort (); + /* Once all the arguments are in their respective place, we're + ready to shift them up into the incoming argument space. */ + if (pass == tail_call_seq) + { + for (i = 0; i < num_actuals; i++) + { + /* Determine whether to pass arg on stack or in register + and the according address to access. */ + rtx src = (args[i].reg != 0) ? args[i].reg : args[i].stack; + + /* This code only handles variables that are being passed + via the stack. That is, extra precautions are required + to pass other types. */ + + /* Determine the destination for each argument. */ + rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset); + rtx addr = plus_constant (virtual_incoming_args_rtx, + INTVAL(slot_offset)); + rtx dest = gen_rtx_MEM (args[i].mode, addr); + + /* A block move might be more appropriate, when the args + are actual structs; not C basic types. */ + emit_move_insn (dest, src); + } + } + /* Generate the actual call instruction. */ emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size, adjusted_args_size.constant, struct_value_size, *************** expand_call (exp, target, ignore) *** 3055,3061 **** flags, & args_so_far); /* Verify that we've deallocated all the stack we used. */ ! if (pass && old_stack_allocated != stack_pointer_delta - pending_stack_adjust) abort (); --- 3171,3177 ---- flags, & args_so_far); /* Verify that we've deallocated all the stack we used. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) && old_stack_allocated != stack_pointer_delta - pending_stack_adjust) abort (); *************** expand_call (exp, target, ignore) *** 3063,3069 **** Test valreg so we don't crash; may safely ignore `const' if return type is void. Disable for PARALLEL return values, because we have no way to move such values into a pseudo register. */ ! if (pass && (flags & ECF_LIBCALL_BLOCK)) { rtx insns; --- 3179,3186 ---- Test valreg so we don't crash; may safely ignore `const' if return type is void. Disable for PARALLEL return values, because we have no way to move such values into a pseudo register. */ ! if ((pass == normal_call_seq || pass == tail_call_seq) ! && (flags & ECF_LIBCALL_BLOCK)) { rtx insns; *************** expand_call (exp, target, ignore) *** 3105,3111 **** valreg = temp; } } ! else if (pass && (flags & ECF_MALLOC)) { rtx temp = gen_reg_rtx (GET_MODE (valreg)); rtx last, insns; --- 3222,3229 ---- valreg = temp; } } ! else if ((pass == normal_call_seq || pass == tail_call_seq) ! && (flags & ECF_MALLOC)) { rtx temp = gen_reg_rtx (GET_MODE (valreg)); rtx last, insns; *************** expand_call (exp, target, ignore) *** 3132,3139 **** /* For calls to `setjmp', etc., inform flow.c it should complain if nonvolatile values are live. For functions that cannot return, inform flow that control does not fall through. */ ! ! if ((flags & (ECF_NORETURN | ECF_LONGJMP)) || pass == 0) { /* The barrier must be emitted immediately after the CALL_INSN. Some ports emit more --- 3250,3258 ---- /* For calls to `setjmp', etc., inform flow.c it should complain if nonvolatile values are live. For functions that cannot return, inform flow that control does not fall through. */ ! if ((flags & (ECF_NORETURN | ECF_LONGJMP)) ! || pass == sib_call_seq ! || pass == tail_call_seq) { /* The barrier must be emitted immediately after the CALL_INSN. Some ports emit more *************** expand_call (exp, target, ignore) *** 3286,3292 **** stack_usage_map = initial_stack_usage_map; sibcall_failure = 1; } ! else if (ACCUMULATE_OUTGOING_ARGS && pass) { #ifdef REG_PARM_STACK_SPACE if (save_area) --- 3405,3412 ---- stack_usage_map = initial_stack_usage_map; sibcall_failure = 1; } ! else if (ACCUMULATE_OUTGOING_ARGS ! && (pass == normal_call_seq || pass == tail_call_seq)) { #ifdef REG_PARM_STACK_SPACE if (save_area) *************** expand_call (exp, target, ignore) *** 3330,3336 **** if (args[i].aligned_regs) free (args[i].aligned_regs); ! if (pass == 0) { /* Undo the fake expand_start_target_temps we did earlier. If there had been any cleanups created, we've already set --- 3450,3456 ---- if (args[i].aligned_regs) free (args[i].aligned_regs); ! if (pass == sib_call_seq) { /* Undo the fake expand_start_target_temps we did earlier. If there had been any cleanups created, we've already set *************** expand_call (exp, target, ignore) *** 3341,3349 **** insns = get_insns (); end_sequence (); ! if (pass == 0) { ! tail_call_insns = insns; /* Restore the pending stack adjustment now that we have finished generating the sibling call sequence. */ --- 3461,3469 ---- insns = get_insns (); end_sequence (); ! if (pass == sib_call_seq) { ! sib_call_insns = insns; /* Restore the pending stack adjustment now that we have finished generating the sibling call sequence. */ *************** expand_call (exp, target, ignore) *** 3361,3372 **** sbitmap_free (stored_args_map); } ! else normal_call_insns = insns; /* If something prevents making this a sibling call, zero out the sequence. */ if (sibcall_failure) tail_call_insns = NULL_RTX; } --- 3481,3499 ---- sbitmap_free (stored_args_map); } ! else if (pass == normal_call_seq) normal_call_insns = insns; + else if (pass == tail_call_seq) + tail_call_insns = insns; + else + abort (); /* If something prevents making this a sibling call, zero out the sequence. */ if (sibcall_failure) + sib_call_insns = NULL_RTX; + + if (tailcall_failure) tail_call_insns = NULL_RTX; } *************** expand_call (exp, target, ignore) *** 3393,3402 **** && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) replace_call_placeholder (insn, sibcall_use_normal); ! /* If this was a potential tail recursion site, then emit a ! CALL_PLACEHOLDER with the normal and the tail recursion streams. ! One of them will be selected later. */ ! if (tail_recursion_insns || tail_call_insns) { /* The tail recursion label must be kept around. We could expose its use in the CALL_PLACEHOLDER, but that creates unwanted edges --- 3520,3534 ---- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) replace_call_placeholder (insn, sibcall_use_normal); ! for (insn = sib_call_insns; insn; insn = NEXT_INSN (insn)) ! if (GET_CODE (insn) == CALL_INSN ! && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) ! replace_call_placeholder (insn, sibcall_use_normal); ! ! /* If this was a potential tail call/recursion site, then emit a ! CALL_PLACEHOLDER with the different streams. One of them will ! be selected later. */ ! if (sib_call_insns || tail_recursion_insns || tail_call_insns) { /* The tail recursion label must be kept around. We could expose its use in the CALL_PLACEHOLDER, but that creates unwanted edges *************** expand_call (exp, target, ignore) *** 3407,3414 **** if (tail_recursion_insns) LABEL_PRESERVE_P (tail_recursion_label) = 1; emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns, ! tail_call_insns, tail_recursion_insns, tail_recursion_label)); } else --- 3539,3547 ---- if (tail_recursion_insns) LABEL_PRESERVE_P (tail_recursion_label) = 1; emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns, ! sib_call_insns, tail_recursion_insns, + tail_call_insns, tail_recursion_label)); } else diff -b -w -B -d -p -c gcc-3.2/gcc/cfgbuild.c gcc-3.2-cvs/gcc/cfgbuild.c *** gcc-3.2/gcc/cfgbuild.c Sun Dec 23 02:51:07 2001 --- gcc-3.2-cvs/gcc/cfgbuild.c Mon Sep 2 13:53:03 2002 *************** find_basic_blocks_1 (f) *** 544,552 **** lvl = find_label_refs (XEXP (PATTERN (insn), 0), lvl); lvl = find_label_refs (XEXP (PATTERN (insn), 1), lvl); lvl = find_label_refs (XEXP (PATTERN (insn), 2), lvl); /* Record its tail recursion label, if any. */ if (XEXP (PATTERN (insn), 3) != NULL_RTX) ! trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 3), trll); } break; --- 544,553 ---- lvl = find_label_refs (XEXP (PATTERN (insn), 0), lvl); lvl = find_label_refs (XEXP (PATTERN (insn), 1), lvl); lvl = find_label_refs (XEXP (PATTERN (insn), 2), lvl); + lvl = find_label_refs (XEXP (PATTERN (insn), 3), lvl); /* Record its tail recursion label, if any. */ if (XEXP (PATTERN (insn), 3) != NULL_RTX) ! trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 4), trll); } break; Common subdirectories: gcc-3.2/gcc/config and gcc-3.2-cvs/gcc/config Common subdirectories: gcc-3.2/gcc/cp and gcc-3.2-cvs/gcc/cp Common subdirectories: gcc-3.2/gcc/doc and gcc-3.2-cvs/gcc/doc diff -b -w -B -d -p -c gcc-3.2/gcc/except.c gcc-3.2-cvs/gcc/except.c *** gcc-3.2/gcc/except.c Wed Apr 17 11:48:17 2002 --- gcc-3.2-cvs/gcc/except.c Mon Sep 2 13:53:08 2002 *************** convert_from_eh_region_ranges_1 (pinsns, *** 1396,1401 **** --- 1396,1403 ---- sp, cur); convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2), sp, cur); + convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 3), + sp, cur); } } } *************** can_throw_internal (insn) *** 3082,3088 **** && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 3; ++i) { rtx sub = XEXP (PATTERN (insn), i); for (; sub ; sub = NEXT_INSN (sub)) --- 3084,3090 ---- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 4; ++i) { rtx sub = XEXP (PATTERN (insn), i); for (; sub ; sub = NEXT_INSN (sub)) *************** can_throw_external (insn) *** 3143,3149 **** && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 3; ++i) { rtx sub = XEXP (PATTERN (insn), i); for (; sub ; sub = NEXT_INSN (sub)) --- 3145,3151 ---- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 4; ++i) { rtx sub = XEXP (PATTERN (insn), i); for (; sub ; sub = NEXT_INSN (sub)) Common subdirectories: gcc-3.2/gcc/f and gcc-3.2-cvs/gcc/f diff -b -w -B -d -p -c gcc-3.2/gcc/final.c gcc-3.2-cvs/gcc/final.c *** gcc-3.2/gcc/final.c Sat May 25 07:26:50 2002 --- gcc-3.2-cvs/gcc/final.c Sun Sep 1 18:26:20 2002 *************** leaf_function_p () *** 3838,3849 **** for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { if (GET_CODE (insn) == CALL_INSN ! && ! SIBLING_CALL_P (insn)) return 0; if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN ! && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } for (link = current_function_epilogue_delay_list; --- 3838,3850 ---- for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { if (GET_CODE (insn) == CALL_INSN ! && (! SIBLING_CALL_P (insn) || TAIL_CALL_P (insn))) return 0; if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN ! && (! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)) ! || TAIL_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))) return 0; } for (link = current_function_epilogue_delay_list; *************** leaf_function_p () *** 3858,3864 **** if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN ! && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) return 0; } --- 3859,3866 ---- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN ! && (! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)) ! || TAIL_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))) return 0; } Common subdirectories: gcc-3.2/gcc/fixinc and gcc-3.2-cvs/gcc/fixinc diff -b -w -B -d -p -c gcc-3.2/gcc/flags.h gcc-3.2-cvs/gcc/flags.h *** gcc-3.2/gcc/flags.h Fri Mar 22 10:12:21 2002 --- gcc-3.2-cvs/gcc/flags.h Sun Sep 1 18:26:21 2002 *************** extern int flag_volatile_static; *** 333,338 **** --- 333,342 ---- extern int flag_optimize_sibling_calls; + /* Nonzero allows GCC to optimize general tail calls. */ + + extern int flag_optimize_tail_calls; + /* Nonzero means the front end generally wants `errno' maintained by math operations, like built-in SQRT. */ diff -b -w -B -d -p -c gcc-3.2/gcc/function.c gcc-3.2-cvs/gcc/function.c *** gcc-3.2/gcc/function.c Sun Jun 23 00:29:26 2002 --- gcc-3.2-cvs/gcc/function.c Mon Sep 2 13:53:09 2002 *************** fixup_var_refs_insns (insn, var, promote *** 1673,1679 **** rtx next = NEXT_INSN (insn); /* CALL_PLACEHOLDERs are special; we have to switch into each of ! the three sequences they (potentially) contain, and process them recursively. The CALL_INSN itself is not interesting. */ if (GET_CODE (insn) == CALL_INSN --- 1673,1679 ---- rtx next = NEXT_INSN (insn); /* CALL_PLACEHOLDERs are special; we have to switch into each of ! the four sequences they (potentially) contain, and process them recursively. The CALL_INSN itself is not interesting. */ if (GET_CODE (insn) == CALL_INSN *************** fixup_var_refs_insns (insn, var, promote *** 1683,1689 **** /* Look at the Normal call, sibling call and tail recursion sequences attached to the CALL_PLACEHOLDER. */ ! for (i = 0; i < 3; i++) { rtx seq = XEXP (PATTERN (insn), i); if (seq) --- 1683,1689 ---- /* Look at the Normal call, sibling call and tail recursion sequences attached to the CALL_PLACEHOLDER. */ ! for (i = 0; i < 4; i++) { rtx seq = XEXP (PATTERN (insn), i); if (seq) *************** identify_blocks_1 (insns, block_vector, *** 5902,5907 **** --- 5902,5910 ---- if (XEXP (cp, 2)) block_vector = identify_blocks_1 (XEXP (cp, 2), block_vector, end_block_vector, block_stack); + if (XEXP (cp, 3)) + block_vector = identify_blocks_1 (XEXP (cp, 3), block_vector, + end_block_vector, block_stack); } } *************** reorder_blocks_1 (insns, current_block, *** 6022,6027 **** --- 6025,6032 ---- reorder_blocks_1 (XEXP (cp, 1), current_block, p_block_stack); if (XEXP (cp, 2)) reorder_blocks_1 (XEXP (cp, 2), current_block, p_block_stack); + if (XEXP (cp, 3)) + reorder_blocks_1 (XEXP (cp, 3), current_block, p_block_stack); } } } Common subdirectories: gcc-3.2/gcc/ginclude and gcc-3.2-cvs/gcc/ginclude diff -b -w -B -d -p -c gcc-3.2/gcc/integrate.c gcc-3.2-cvs/gcc/integrate.c *** gcc-3.2/gcc/integrate.c Sat Apr 13 05:17:54 2002 --- gcc-3.2-cvs/gcc/integrate.c Mon Sep 2 13:53:11 2002 *************** save_parm_insns (insn, first_nonparm_ins *** 523,536 **** note_stores (PATTERN (insn), note_modified_parmregs, NULL); /* If this is a CALL_PLACEHOLDER insn then we need to look into the ! three attached sequences: normal call, sibling call and tail ! recursion. */ if (GET_CODE (insn) == CALL_INSN && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 3; i++) save_parm_insns (XEXP (PATTERN (insn), i), first_nonparm_insn); } --- 523,536 ---- note_stores (PATTERN (insn), note_modified_parmregs, NULL); /* If this is a CALL_PLACEHOLDER insn then we need to look into the ! four attached sequences: normal call, sibling call, tail ! recursion and tail call. */ if (GET_CODE (insn) == CALL_INSN && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 4; i++) save_parm_insns (XEXP (PATTERN (insn), i), first_nonparm_insn); } *************** copy_insn_list (insns, map, static_chain *** 1559,1572 **** case CALL_INSN: /* If this is a CALL_PLACEHOLDER insn then we need to copy the ! three attached sequences: normal call, sibling call and tail ! recursion. */ if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { ! rtx sequence[3]; rtx tail_label; ! for (i = 0; i < 3; i++) { rtx seq; --- 1559,1572 ---- case CALL_INSN: /* If this is a CALL_PLACEHOLDER insn then we need to copy the ! four attached sequences: normal call, sibling call, tail ! recursion and tail call. */ if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { ! rtx sequence[4]; rtx tail_label; ! for (i = 0; i < 4; i++) { rtx seq; *************** copy_insn_list (insns, map, static_chain *** 1583,1595 **** /* Find the new tail recursion label. It will already be substituted into sequence[2]. */ ! tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 3), map, 0); copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, sequence[0], sequence[1], sequence[2], tail_label)); break; } --- 1583,1600 ---- /* Find the new tail recursion label. It will already be substituted into sequence[2]. */ ! tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 4), map, 0); + /* The last call sequence contains the general tail call + optimisation. */ + /* FIXME: squeeze sequence[3] between sequence[2] and + tail_label. */ copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, sequence[0], sequence[1], sequence[2], + sequence[3], tail_label)); break; } *************** copy_insn_list (insns, map, static_chain *** 1598,1603 **** --- 1603,1609 ---- copy = emit_call_insn (pattern); SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn); + TAIL_CALL_P (copy) = TAIL_CALL_P (insn); CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn); /* Because the USAGE information potentially contains objects other *************** copy_insn_notes (insns, map, eh_region_o *** 1742,1748 **** && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 3; i++) copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset); } --- 1748,1754 ---- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) { int i; ! for (i = 0; i < 4; i++) copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset); } Common subdirectories: gcc-3.2/gcc/intl and gcc-3.2-cvs/gcc/intl Common subdirectories: gcc-3.2/gcc/java and gcc-3.2-cvs/gcc/java diff -b -w -B -d -p -c gcc-3.2/gcc/jump.c gcc-3.2-cvs/gcc/jump.c *** gcc-3.2/gcc/jump.c Wed Apr 10 06:38:58 2002 --- gcc-3.2-cvs/gcc/jump.c Mon Sep 2 13:53:11 2002 *************** mark_all_labels (f) *** 236,250 **** mark_all_labels (XEXP (PATTERN (insn), 0)); mark_all_labels (XEXP (PATTERN (insn), 1)); mark_all_labels (XEXP (PATTERN (insn), 2)); /* Canonicalize the tail recursion label attached to the CALL_PLACEHOLDER insn. */ ! if (XEXP (PATTERN (insn), 3)) { rtx label_ref = gen_rtx_LABEL_REF (VOIDmode, XEXP (PATTERN (insn), 3)); mark_jump_label (label_ref, insn, 0); ! XEXP (PATTERN (insn), 3) = XEXP (label_ref, 0); } continue; --- 236,251 ---- mark_all_labels (XEXP (PATTERN (insn), 0)); mark_all_labels (XEXP (PATTERN (insn), 1)); mark_all_labels (XEXP (PATTERN (insn), 2)); + mark_all_labels (XEXP (PATTERN (insn), 3)); /* Canonicalize the tail recursion label attached to the CALL_PLACEHOLDER insn. */ ! if (XEXP (PATTERN (insn), 4)) { rtx label_ref = gen_rtx_LABEL_REF (VOIDmode, XEXP (PATTERN (insn), 3)); mark_jump_label (label_ref, insn, 0); ! XEXP (PATTERN (insn), 4) = XEXP (label_ref, 0); } continue; diff -b -w -B -d -p -c gcc-3.2/gcc/mkinstalldirs gcc-3.2-cvs/gcc/mkinstalldirs *** gcc-3.2/gcc/mkinstalldirs Sun Sep 5 01:08:55 1999 --- gcc-3.2-cvs/gcc/mkinstalldirs Thu Aug 22 16:25:59 2002 *************** *** 4,10 **** # Created: 1993-05-16 # Public domain ! # $Id: mkinstalldirs,v 1.2 1999/09/04 15:08:55 law Exp $ errstatus=0 --- 4,10 ---- # Created: 1993-05-16 # Public domain ! # $Id: mkinstalldirs,v 1.1.1.1 2002/08/22 06:25:59 baueran Exp $ errstatus=0 Common subdirectories: gcc-3.2/gcc/objc and gcc-3.2-cvs/gcc/objc Common subdirectories: gcc-3.2/gcc/po and gcc-3.2-cvs/gcc/po diff -b -w -B -d -p -c gcc-3.2/gcc/rtl.def gcc-3.2-cvs/gcc/rtl.def *** gcc-3.2/gcc/rtl.def Tue Feb 19 13:53:26 2002 --- gcc-3.2-cvs/gcc/rtl.def Fri Aug 23 15:11:46 2002 *************** DEF_RTL_EXPR(CONSTANT_P_RTX, "constant_p *** 955,961 **** This method of tail-call elimination is intended to be replaced by tree-based optimizations once front-end conversions are complete. */ ! DEF_RTL_EXPR(CALL_PLACEHOLDER, "call_placeholder", "uuuu", 'x') /* Describes a merge operation between two vector values. Operands 0 and 1 are the vectors to be merged, operand 2 is a bitmask --- 955,961 ---- This method of tail-call elimination is intended to be replaced by tree-based optimizations once front-end conversions are complete. */ ! DEF_RTL_EXPR(CALL_PLACEHOLDER, "call_placeholder", "uuuuu", 'x') /* Describes a merge operation between two vector values. Operands 0 and 1 are the vectors to be merged, operand 2 is a bitmask diff -b -w -B -d -p -c gcc-3.2/gcc/rtl.h gcc-3.2-cvs/gcc/rtl.h *** gcc-3.2/gcc/rtl.h Sun May 19 19:05:27 2002 --- gcc-3.2-cvs/gcc/rtl.h Mon Sep 2 14:10:50 2002 *************** struct rtx_def *** 133,138 **** --- 133,139 ---- LINK_COST_ZERO in an INSN_LIST. SET_IS_RETURN_P in a SET. */ unsigned int jump : 1; + unsigned int tailcall : 1; /* 1 in an INSN if it can call another function. LINK_COST_FREE in an INSN_LIST. */ unsigned int call : 1; *************** extern void rtvec_check_failed_bounds PA *** 419,425 **** /* 1 if insn is a call to a const or pure function. */ #define CONST_OR_PURE_CALL_P(INSN) ((INSN)->unchanging) ! /* 1 if insn (assumed to be a CALL_INSN) is a sibling call. */ #define SIBLING_CALL_P(INSN) ((INSN)->jump) /* 1 if insn is a branch that should not unconditionally execute its --- 420,428 ---- /* 1 if insn is a call to a const or pure function. */ #define CONST_OR_PURE_CALL_P(INSN) ((INSN)->unchanging) ! /* 1 if insn (assumed to be a CALL_INSN) is a call in tail ! position (sibcall or even a more general tail call). */ ! #define TAIL_CALL_P(INSN) ((INSN)->tailcall) #define SIBLING_CALL_P(INSN) ((INSN)->jump) /* 1 if insn is a branch that should not unconditionally execute its *************** extern rtx addr_side_effect_eval PARAMS *** 2106,2112 **** typedef enum { sibcall_use_normal = 1, sibcall_use_tail_recursion, ! sibcall_use_sibcall } sibcall_use_t; extern void optimize_sibling_and_tail_recursive_calls PARAMS ((void)); --- 2109,2116 ---- typedef enum { sibcall_use_normal = 1, sibcall_use_tail_recursion, ! sibcall_use_sibcall, ! sibcall_use_tailcall } sibcall_use_t; extern void optimize_sibling_and_tail_recursive_calls PARAMS ((void)); diff -b -w -B -d -p -c gcc-3.2/gcc/sibcall.c gcc-3.2-cvs/gcc/sibcall.c *** gcc-3.2/gcc/sibcall.c Sun Apr 7 05:37:38 2002 --- gcc-3.2-cvs/gcc/sibcall.c Mon Sep 9 11:35:18 2002 *************** sequence_uses_addressof (seq) *** 461,466 **** --- 461,469 ---- if (XEXP (PATTERN (insn), 2) != NULL_RTX && sequence_uses_addressof (XEXP (PATTERN (insn), 2))) return 1; + if (XEXP (PATTERN (insn), 3) != NULL_RTX + && sequence_uses_addressof (XEXP (PATTERN (insn), 3))) + return 1; } else if (uses_addressof (PATTERN (insn)) || (REG_NOTES (insn) && uses_addressof (REG_NOTES (insn)))) *************** replace_call_placeholder (insn, use) *** 540,546 **** rtx insn; sibcall_use_t use; { ! if (use == sibcall_use_tail_recursion) emit_insns_before (XEXP (PATTERN (insn), 2), insn); else if (use == sibcall_use_sibcall) emit_insns_before (XEXP (PATTERN (insn), 1), insn); --- 543,551 ---- rtx insn; sibcall_use_t use; { ! if (use == sibcall_use_tailcall) ! emit_insns_before (XEXP (PATTERN (insn), 3), insn); ! else if (use == sibcall_use_tail_recursion) emit_insns_before (XEXP (PATTERN (insn), 2), insn); else if (use == sibcall_use_sibcall) emit_insns_before (XEXP (PATTERN (insn), 1), insn); *************** optimize_sibling_and_tail_recursive_call *** 575,580 **** --- 580,586 ---- basic_block alternate_exit = EXIT_BLOCK_PTR; bool no_sibcalls_this_function = false; int successful_sibling_call = 0; + int successful_tail_call = 0; int replaced_call_placeholder = 0; edge e; *************** optimize_sibling_and_tail_recursive_call *** 680,685 **** --- 686,692 ---- { int sibcall = (XEXP (PATTERN (insn), 1) != NULL_RTX); int tailrecursion = (XEXP (PATTERN (insn), 2) != NULL_RTX); + int tailcall = (XEXP (PATTERN (insn), 3) != NULL_RTX); basic_block call_block = BLOCK_FOR_INSN (insn); /* alloca (until we have stack slot life analysis) inhibits *************** optimize_sibling_and_tail_recursive_call *** 688,701 **** may take the address of an argument. */ if (current_function_calls_alloca || current_function_varargs || current_function_stdarg) ! sibcall = 0; /* See if there are any reasons we can't perform either sibling or tail call optimizations. We must be careful with stack slots which are live at potential optimization sites. */ if (no_sibcalls_this_function - /* ??? Overly conservative. */ - || frame_offset /* Any function that calls setjmp might have longjmp called from any called function. ??? We really should represent this properly in the CFG so that this needn't be special cased. */ --- 695,706 ---- may take the address of an argument. */ if (current_function_calls_alloca || current_function_varargs || current_function_stdarg) ! sibcall = 0, tailcall = 0; /* See if there are any reasons we can't perform either sibling or tail call optimizations. We must be careful with stack slots which are live at potential optimization sites. */ if (no_sibcalls_this_function /* Any function that calls setjmp might have longjmp called from any called function. ??? We really should represent this properly in the CFG so that this needn't be special cased. */ *************** optimize_sibling_and_tail_recursive_call *** 710,715 **** --- 715,728 ---- /* If this call doesn't end the block, there are operations at the end of the block which we must execute after returning. */ || ! call_ends_block_p (insn, call_block->end)) + sibcall = 0, tailrecursion = 0, tailcall = 0; + + /* Another reason why sibling calls fail: if the stack frame size is + positive. This can be overcome by letting the front-end do live + analysis and tell the back-end it's safe to do tail call + optimization. For now, we just ignore the restriction though and + keep optimizing the super sib calls anyway. */ + if (frame_offset) sibcall = 0, tailrecursion = 0; /* Select a set of insns to implement the call and emit them. *************** optimize_sibling_and_tail_recursive_call *** 718,730 **** if (sibcall) successful_sibling_call = 1; replaced_call_placeholder = 1; ! replace_call_placeholder (insn, ! tailrecursion != 0 ! ? sibcall_use_tail_recursion ! : sibcall != 0 ! ? sibcall_use_sibcall ! : sibcall_use_normal); } } --- 731,752 ---- if (sibcall) successful_sibling_call = 1; + if (tailcall) + successful_tail_call = 1; + replaced_call_placeholder = 1; ! ! /* For the sake of readability, the different call sequences ! are put into if-conditions with the most restrictive choice ! at the top and the most general call method at the bottom. */ ! if (tailrecursion) ! replace_call_placeholder (insn, sibcall_use_tail_recursion); ! else if (sibcall) ! replace_call_placeholder (insn, sibcall_use_sibcall); ! else if (tailcall) ! replace_call_placeholder (insn, sibcall_use_tailcall); ! else ! replace_call_placeholder (insn, sibcall_use_normal); } } Common subdirectories: gcc-3.2/gcc/testsuite and gcc-3.2-cvs/gcc/testsuite diff -b -w -B -d -p -c gcc-3.2/gcc/toplev.c gcc-3.2-cvs/gcc/toplev.c *** gcc-3.2/gcc/toplev.c Mon May 27 15:48:15 2002 --- gcc-3.2-cvs/gcc/toplev.c Mon Sep 9 11:36:52 2002 *************** int flag_no_peephole = 0; *** 570,575 **** --- 570,579 ---- int flag_optimize_sibling_calls = 0; + /* Nonzero allows GCC to optimize general tail calls. */ + + int flag_optimize_tail_calls = 0; + /* Nonzero means the front end generally wants `errno' maintained by math operations, like built-in SQRT. */ *************** static const lang_independent_options f_ *** 973,978 **** --- 977,984 ---- N_("When possible do not generate stack frames") }, {"optimize-sibling-calls", &flag_optimize_sibling_calls, 1, N_("Optimize sibling and tail recursive calls") }, + {"optimize-tail-calls", &flag_optimize_tail_calls, 1, + N_("Optimize general tail calls") }, {"cse-follow-jumps", &flag_cse_follow_jumps, 1, N_("When running CSE, follow jumps to their targets") }, {"cse-skip-blocks", &flag_cse_skip_blocks, 1, *************** rest_of_compilation (decl) *** 2565,2571 **** /* We may have potential sibling or tail recursion sites. Select one (of possibly multiple) methods of performing the call. */ ! if (flag_optimize_sibling_calls) { timevar_push (TV_JUMP); open_dump_file (DFI_sibling, decl); --- 2571,2577 ---- /* We may have potential sibling or tail recursion sites. Select one (of possibly multiple) methods of performing the call. */ ! if (flag_optimize_sibling_calls || flag_optimize_tail_calls) { timevar_push (TV_JUMP); open_dump_file (DFI_sibling, decl); diff -b -w -B -d -p -c gcc-3.2/gcc/tree.c gcc-3.2-cvs/gcc/tree.c *** gcc-3.2/gcc/tree.c Sat Apr 27 09:46:01 2002 --- gcc-3.2-cvs/gcc/tree.c Mon Sep 2 16:04:01 2002 *************** get_callee_fndecl (call) *** 4449,4454 **** --- 4449,4455 ---- return TREE_OPERAND (addr, 0); /* We couldn't figure out what was being called. */ + warning ("indirect call, not recognized"); return NULL_TREE; } diff -b -w -B -d -p -c gcc-3.2/gcc/unroll.c gcc-3.2-cvs/gcc/unroll.c *** gcc-3.2/gcc/unroll.c Sat Jun 15 11:12:06 2002 --- gcc-3.2-cvs/gcc/unroll.c Sun Sep 1 18:26:54 2002 *************** copy_loop_body (loop, copy_start, copy_e *** 2222,2227 **** --- 2222,2228 ---- copy = emit_call_insn (pattern); REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map); SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn); + TAIL_CALL_P (copy) = TAIL_CALL_P (insn); /* Because the USAGE information potentially contains objects other than hard registers, we need to copy it. */