X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcalls.c;h=46843941dac3961337b2e21e9aad6cbc286c1b61;hb=8313a7823adb78d51bc8099f15e7c665d8dbb64c;hp=073a23c2b234156a0e0c837fedcfdd1e791b55d5;hpb=aebed4a184154713b49a4b699447f2f1b852bdf9;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/calls.c b/gcc/calls.c index 073a23c2b23..46843941dac 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -60,7 +60,7 @@ struct arg_data /* Initially-compute RTL value for argument; only for const functions. */ rtx initial_value; /* Register to pass this argument in, 0 if passed on stack, or an - EXPR_LIST if the arg is to be copied into multiple different + PARALLEL if the arg is to be copied into multiple non-contiguous registers. */ rtx reg; /* If REG was promoted from the actual mode of the argument expression, @@ -261,7 +261,7 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen) funexp = protect_from_queue (funexp, 0); if (fndecl != 0) - /* Get possible static chain value for nested function in C. */ + /* Get possible static chain value for nested function in C. */ static_chain_value = lookup_static_chain (fndecl); /* Make a valid memory address and copy constants thru pseudo-regs, @@ -532,7 +532,6 @@ expand_call (exp, target, ignore) /* Nonzero if a reg parm has been scanned. */ int reg_parm_seen; /* Nonzero if this is an indirect function call. */ - int current_call_is_indirect = 0; /* Nonzero if we must avoid push-insns in the args for this call. If stack space is allocated for register parameters, but not by the @@ -607,7 +606,8 @@ expand_call (exp, target, ignore) if (!flag_no_inline && fndecl != current_function_decl && DECL_INLINE (fndecl) - && DECL_SAVED_INSNS (fndecl)) + && DECL_SAVED_INSNS (fndecl) + && RTX_INTEGRATED_P (DECL_SAVED_INSNS (fndecl))) is_integrable = 1; else if (! TREE_ADDRESSABLE (fndecl)) { @@ -739,7 +739,9 @@ expand_call (exp, target, ignore) if (stack_arg_under_construction || i >= 0) { - rtx insn = NEXT_INSN (before_call), seq; + rtx first_insn + = before_call ? NEXT_INSN (before_call) : get_insns (); + rtx insn, seq; /* Look for a call in the inline function code. If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is @@ -747,7 +749,7 @@ expand_call (exp, target, ignore) to scan the insns. */ if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0) - for (; insn; insn = NEXT_INSN (insn)) + for (insn = first_insn; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == CALL_INSN) break; @@ -779,7 +781,7 @@ expand_call (exp, target, ignore) NULL_RTX, BITS_PER_UNIT); seq = get_insns (); end_sequence (); - emit_insns_before (seq, NEXT_INSN (before_call)); + emit_insns_before (seq, first_insn); emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); } } @@ -815,15 +817,6 @@ expand_call (exp, target, ignore) if (fndecl && DECL_NAME (fndecl)) name = IDENTIFIER_POINTER (DECL_NAME (fndecl)); - /* On some machines (such as the PA) indirect calls have a different - calling convention than normal calls. FUNCTION_ARG in the target - description can look at current_call_is_indirect to determine which - calling convention to use. */ - current_call_is_indirect = (fndecl == 0); -#if 0 - = TREE_CODE (TREE_OPERAND (exp, 0)) == NON_LVALUE_EXPR ? 1 : 0; -#endif - #if 0 /* Unless it's a call to a specific function that isn't alloca, if it has one argument, we must assume it might be alloca. */ @@ -912,8 +905,13 @@ expand_call (exp, target, ignore) we make. */ push_temp_slots (); - /* Start updating where the next arg would go. */ - INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX); + /* Start updating where the next arg would go. + + On some machines (such as the PA) indirect calls have a different + calling convention than normal calls. The last argument in + INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call + or not. */ + INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, (fndecl == 0)); /* If struct_value_rtx is 0, it means pass the address as if it were an extra parameter. */ @@ -1085,6 +1083,7 @@ expand_call (exp, target, ignore) MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type); store_expr (args[i].tree_value, copy, 0); + is_const = 0; args[i].tree_value = build1 (ADDR_EXPR, build_pointer_type (type), @@ -1113,12 +1112,12 @@ expand_call (exp, target, ignore) args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type); - /* If FUNCTION_ARG returned an (expr_list (nil) FOO), it means that - we are to pass this arg in the register(s) designated by FOO, but - also to pass it in the stack. */ - if (args[i].reg && GET_CODE (args[i].reg) == EXPR_LIST - && XEXP (args[i].reg, 0) == 0) - args[i].pass_on_stack = 1, args[i].reg = XEXP (args[i].reg, 1); + /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]), + it means that we are to pass this arg in the register(s) designated + by the PARALLEL, but also to pass it in the stack. */ + if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL + && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0) + args[i].pass_on_stack = 1; /* If this is an addressable type, we must preallocate the stack since we must evaluate the object into its final location. @@ -1393,8 +1392,9 @@ expand_call (exp, target, ignore) int needed = args_size.constant; - /* Store the maximum argument space used. It will be pushed by the - prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow checking). */ + /* Store the maximum argument space used. It will be pushed by + the prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow + checking). */ if (needed > current_function_outgoing_args_size) current_function_outgoing_args_size = needed; @@ -1612,7 +1612,7 @@ expand_call (exp, target, ignore) } /* Precompute all register parameters. It isn't safe to compute anything - once we have started filling any specific hard regs. */ + once we have started filling any specific hard regs. */ reg_parm_seen = 0; for (i = 0; i < num_actuals; i++) if (args[i].reg != 0 && ! args[i].pass_on_stack) @@ -1847,20 +1847,12 @@ expand_call (exp, target, ignore) for (i = 0; i < num_actuals; i++) { - rtx list = args[i].reg; + rtx reg = args[i].reg; int partial = args[i].partial; + int nregs; - while (list) + if (reg) { - rtx reg; - int nregs; - - /* Process each register that needs to get this arg. */ - if (GET_CODE (list) == EXPR_LIST) - reg = XEXP (list, 0), list = XEXP (list, 1); - else - reg = list, list = 0; - /* Set to non-negative if must move a word at a time, even if just one word (e.g, partial == 1 && mode == DFmode). Set to -1 if we just use a normal move insn. This value can be zero if the @@ -1871,11 +1863,17 @@ expand_call (exp, target, ignore) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) : -1)); + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + + if (GET_CODE (reg) == PARALLEL) + emit_group_load (reg, args[i].value); + /* If simple case, just do move. If normal partial, store_one_arg has already loaded the register for us. In all other cases, load the register(s) from memory. */ - if (nregs == -1) + else if (nregs == -1) emit_move_insn (reg, args[i].value); /* If we have pre-computed the values to put in the registers in @@ -1886,19 +1884,19 @@ expand_call (exp, target, ignore) emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j), args[i].aligned_regs[j]); - else if (args[i].partial == 0 || args[i].pass_on_stack) + else if (partial == 0 || args[i].pass_on_stack) move_block_to_reg (REGNO (reg), validize_mem (args[i].value), nregs, args[i].mode); - if (nregs == -1) + /* Handle calls that pass values in multiple non-contiguous + locations. The Irix 6 ABI has examples of this. */ + if (GET_CODE (reg) == PARALLEL) + use_group_regs (&call_fusage, reg); + else if (nregs == -1) use_reg (&call_fusage, reg); else use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs); - - /* PARTIAL referred only to the first register, so clear it for the - next time. */ - partial = 0; } } @@ -2033,6 +2031,20 @@ expand_call (exp, target, ignore) If they refer to the same register, this move will be a no-op, except when function inlining is being done. */ emit_move_insn (target, valreg); + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (valreg) == PARALLEL) + { + if (target == 0) + { + int bytes = int_size_in_bytes (TREE_TYPE (exp)); + target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0); + MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp)); + preserve_temp_slots (target); + } + + emit_group_store (target, valreg); + } else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { /* Some machines (the PA for example) want to return all small @@ -2059,7 +2071,7 @@ expand_call (exp, target, ignore) copy it into a new pseudo which is a full word. */ if (GET_MODE (valreg) != BLKmode && GET_MODE_SIZE (GET_MODE (valreg)) < UNITS_PER_WORD) - valreg = convert_to_mode (SImode, valreg, + valreg = convert_to_mode (word_mode, valreg, TREE_UNSIGNED (TREE_TYPE (exp))); /* Structures whose size is not a multiple of a word are aligned @@ -2201,7 +2213,7 @@ expand_call (exp, target, ignore) /* If this was alloca, record the new stack level for nonlocal gotos. Check for the handler slots since we might not have a save area - for non-local gotos. */ + for non-local gotos. */ if (may_be_alloca && nonlocal_goto_handler_slot != 0) emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX); @@ -2257,8 +2269,6 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode, struct arg *argvec; int old_inhibit_defer_pop = inhibit_defer_pop; rtx call_fusage = 0; - /* library calls are never indirect calls. */ - int current_call_is_indirect = 0; VA_START (p, nargs); @@ -2280,7 +2290,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode, argvec = (struct arg *) alloca (nargs * sizeof (struct arg)); - INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun); + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0); args_size.constant = 0; args_size.var = 0; @@ -2329,7 +2339,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode, argvec[count].mode = mode; argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); - if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST) + if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL) abort (); #ifdef FUNCTION_ARG_PARTIAL_NREGS argvec[count].partial @@ -2371,7 +2381,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode, abort (); #endif - FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1); + FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1); } va_end (p); @@ -2536,8 +2546,6 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, rtx mem_value = 0; int pcc_struct_value = 0; int struct_value_size = 0; - /* library calls are never indirect calls. */ - int current_call_is_indirect = 0; int is_const; VA_START (p, nargs); @@ -2588,7 +2596,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg)); - INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun); + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0); args_size.constant = 0; args_size.var = 0; @@ -2632,7 +2640,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, ) args_size.constant += argvec[count].size.constant; - FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree)0, 1); + FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1); count++; } @@ -2679,7 +2687,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, argvec[count].mode = mode; argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1); - if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST) + if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL) abort (); #ifdef FUNCTION_ARG_PARTIAL_NREGS argvec[count].partial @@ -2721,7 +2729,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue, abort (); #endif - FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1); + FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1); } va_end (p); @@ -2964,8 +2972,8 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl, if (argblock && ! variable_size && arg->stack) { #ifdef ARGS_GROW_DOWNWARD - /* stack_slot is negative, but we want to index stack_usage_map */ - /* with positive values. */ + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1; else @@ -3035,12 +3043,6 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl, if (arg->n_aligned_regs != 0) reg = 0; - /* If this is being partially passed in a register, but multiple locations - are specified, we assume that the one partially used is the one that is - listed first. */ - if (reg && GET_CODE (reg) == EXPR_LIST) - reg = XEXP (reg, 0); - /* If this is being passed partially in a register, we can't evaluate it directly into its stack slot. Otherwise, we can. */ if (arg->value == 0)