From 3f1f8d8c042786aa794774d1b529a8f83d15c4c0 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Fri, 18 Dec 1992 23:27:55 +0000 Subject: [PATCH] Pass QI/HI structures like the MIPS compiler; define SIZE_TYPE to be int by default. From-SVN: r2893 --- gcc/config/mips/mips.c | 170 ++++++++++++++++++++++++++-------------- gcc/config/mips/mips.h | 23 +++++- gcc/config/mips/mips.md | 81 ++++++++++++++----- 3 files changed, 192 insertions(+), 82 deletions(-) diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index b4920a747da..8e925b4ac86 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -2413,6 +2413,7 @@ init_cumulative_args (cum, fntype, libname) tree fntype; /* tree ptr for function decl */ rtx libname; /* SYMBOL_REF of library name or 0 */ { + static CUMULATIVE_ARGS zero_cum; tree param, next_param; if (TARGET_DEBUG_E_MODE) @@ -2430,9 +2431,7 @@ init_cumulative_args (cum, fntype, libname) } } - cum->gp_reg_found = 0; - cum->arg_number = 0; - cum->arg_words = 0; + *cum = zero_cum; /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there @@ -2461,7 +2460,7 @@ function_arg_advance (cum, mode, type, named) { if (TARGET_DEBUG_E_MODE) fprintf (stderr, - "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n", + "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n", cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), type, named); @@ -2512,8 +2511,12 @@ function_arg (cum, mode, type, named) tree type; /* type of the argument or 0 if lib support */ int named; /* != 0 for normal args, == 0 for ... args */ { + rtx ret; int regbase = -1; int bias = 0; + int struct_p = ((type != (tree)0) + && (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE)); if (TARGET_DEBUG_E_MODE) fprintf (stderr, @@ -2567,18 +2570,42 @@ function_arg (cum, mode, type, named) if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) { if (TARGET_DEBUG_E_MODE) - fprintf (stderr, "\n"); + fprintf (stderr, "%s\n", struct_p ? ", [struct]" : ""); - return 0; + ret = (rtx)0; + } + else + { + if (regbase == -1) + abort (); + + ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias); + + if (TARGET_DEBUG_E_MODE) + fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias], + struct_p ? ", [struct]" : ""); + + /* The following is a hack in order to pass 1 byte structures + the same way that the MIPS compiler does (namely by passing + the structure in the high byte or half word of the register). + This also makes varargs work. If we have such a structure, + we save the adjustment RTL, and the call define expands will + emit them. For the VOIDmode argument (argument after the + last real argument, pass back a parallel vector holding each + of the adjustments. */ + + if (struct_p && (mode == QImode || mode == HImode)) + { + rtx amount = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode)); + rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias); + cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); + } } - if (regbase == -1) - abort (); + if (mode == VOIDmode && cum->num_adjusts > 0) + ret = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (cum->num_adjusts, cum->adjust)); - if (TARGET_DEBUG_E_MODE) - fprintf (stderr, "%s\n", reg_names[regbase + cum->arg_words + bias]); - - return gen_rtx (REG, mode, regbase + cum->arg_words + bias); + return ret; } @@ -4237,20 +4264,56 @@ mips_expand_prologue () { int regno; long tsize; - tree fndecl = current_function_decl; /* current... is tooo long */ - tree fntype = TREE_TYPE (fndecl); - tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) - ? DECL_ARGUMENTS (fndecl) - : 0; - tree next_arg; - tree cur_arg; rtx tmp_rtx = (rtx)0; char *arg_name = (char *)0; + tree fndecl = current_function_decl; + tree fntype = TREE_TYPE (fndecl); + tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) + ? DECL_ARGUMENTS (fndecl) + : 0; + rtx next_arg_reg; + int i; + tree next_arg; + tree cur_arg; CUMULATIVE_ARGS args_so_far; /* Determine the last argument, and get its name. */ + + INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); + regno = GP_ARG_FIRST; + for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) { + tree type = DECL_ARG_TYPE (cur_arg); + enum machine_mode passed_mode = TYPE_MODE (type); + rtx entry_parm = FUNCTION_ARG (args_so_far, + passed_mode, + DECL_ARG_TYPE (cur_arg), + 1); + + if (entry_parm) + { + int words; + + /* passed in a register, so will get homed automatically */ + if (GET_MODE (entry_parm) == BLKmode) + words = (int_size_in_bytes (type) + 3) / 4; + else + words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; + + regno = REGNO (entry_parm) + words - 1; + } + else + { + regno = GP_ARG_LAST+1; + break; + } + + FUNCTION_ARG_ADVANCE (args_so_far, + passed_mode, + DECL_ARG_TYPE (cur_arg), + 1); + next_arg = TREE_CHAIN (cur_arg); if (next_arg == (tree)0) { @@ -4261,52 +4324,39 @@ mips_expand_prologue () } } + /* In order to pass small structures by value in registers + compatibly with the MIPS compiler, we need to shift the value + into the high part of the register. Function_arg has encoded a + PARALLEL rtx, holding a vector of adjustments to be made as the + next_arg_reg variable, so we split up the insns, and emit them + separately. */ + + next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1); + if (next_arg_reg != (rtx)0 && GET_CODE (next_arg_reg) == PARALLEL) + { + rtvec adjust = XVEC (next_arg_reg, 0); + int num = GET_NUM_ELEM (adjust); + + for (i = 0; i < num; i++) + { + rtx pattern = RTVEC_ELT (adjust, i); + if (GET_CODE (pattern) != SET + || GET_CODE (SET_SRC (pattern)) != ASHIFT) + abort_with_insn (pattern, "Insn is not a shift"); + + PUT_CODE (SET_SRC (pattern), ASHIFTRT); + emit_insn (pattern); + } + } + /* If this function is a varargs function, store any registers that would normally hold arguments ($4 - $7) on the stack. */ if ((TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) - || (arg_name - && (strcmp (arg_name, "__builtin_va_alist") == 0 - || strcmp (arg_name, "va_alist") == 0))) + || (arg_name != (char *)0 + && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0) + || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0)))) { - tree parm; - - regno = GP_ARG_FIRST; - INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); - - for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm)) - { - rtx entry_parm; - enum machine_mode passed_mode; - tree type; - - type = DECL_ARG_TYPE (parm); - passed_mode = TYPE_MODE (type); - entry_parm = FUNCTION_ARG (args_so_far, passed_mode, - DECL_ARG_TYPE (parm), 1); - - if (entry_parm) - { - int words; - - /* passed in a register, so will get homed automatically */ - if (GET_MODE (entry_parm) == BLKmode) - words = (int_size_in_bytes (type) + 3) / 4; - else - words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; - - regno = REGNO (entry_parm) + words - 1; - } - else - { - regno = GP_ARG_LAST+1; - break; - } - - FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, - DECL_ARG_TYPE (parm), 1); - } - for (; regno <= GP_ARG_LAST; regno++) { rtx ptr = stack_pointer_rtx; diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 6ca50ea799c..53636b1e74a 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -483,7 +483,7 @@ while (0) /* Print subsidiary information on the compiler version in use. */ -#define MIPS_VERSION "[AL 1.1, MM 32]" +#define MIPS_VERSION "[AL 1.1, MM 33]" #ifndef MACHINE_TYPE #define MACHINE_TYPE "BSD Mips" @@ -1809,9 +1809,12 @@ extern struct mips_frame_info current_frame_info; */ typedef struct mips_args { - int gp_reg_found; - int arg_number; - int arg_words; + int gp_reg_found; /* whether a gp register was found yet */ + int arg_number; /* argument number */ + int arg_words; /* # total words the arguments take */ + int num_adjusts; /* number of adjustments made */ + /* Adjustments made to args pass in regs. */ + struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS]; } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS @@ -3525,3 +3528,15 @@ while (0) #define MIPS_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK) #define MIPS_MARK_STAB(code) ((code)+CODE_MASK) #define MIPS_UNMARK_STAB(code) ((code)-CODE_MASK) + + +/* Default definitions for size_t and ptrdiff_t. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "unsigned int" +#endif + +#ifndef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" +#endif + diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 1e40306a994..42f3c7c50e5 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -4043,17 +4043,41 @@ move\\t%0,%z4\\n\\ (define_expand "call" [(parallel [(call (match_operand 0 "memory_operand" "m") (match_operand 1 "" "i")) - (clobber (match_operand 2 "" ""))])] ;; overwrite op2 with $31 + (clobber (reg:SI 31)) + (use (match_operand 2 "" "")) ;; next_arg_reg + (use (match_operand 3 "" ""))])] ;; struct_value_size_rtx "" " { rtx addr; - operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); + if (operands[0]) /* eliminate unused code warnings */ + { + addr = XEXP (operands[0], 0); + if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[0], 0) = force_reg (FUNCTION_MODE, addr); - addr = XEXP (operands[0], 0); - if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr)) - XEXP (operands[0], 0) = force_reg (FUNCTION_MODE, addr); + /* In order to pass small structures by value in registers + compatibly with the MIPS compiler, we need to shift the value + into the high part of the register. Function_arg has encoded + a PARALLEL rtx, holding a vector of adjustments to be made + as the next_arg_reg variable, so we split up the insns, + and emit them separately. */ + + if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL) + { + rtvec adjust = XVEC (operands[2], 0); + int num = GET_NUM_ELEM (adjust); + int i; + + for (i = 0; i < num; i++) + emit_insn (RTVEC_ELT (adjust, i)); + } + + emit_call_insn (gen_call_internal (operands[0], operands[1], + gen_rtx (REG, Pmode, GP_REG_FIRST + 31))); + DONE; + } }") (define_insn "call_internal" @@ -4071,15 +4095,13 @@ move\\t%0,%z4\\n\\ else if (GET_CODE (target) == CONST_INT) { operands[0] = target; - operands[1] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); - return \"%*%[li\\t%@,%0\\n\\tjal\\t%1,%@%]\"; + return \"%*%[li\\t%@,%0\\n\\tjal\\t%2,%@%]\"; } else { operands[0] = target; - operands[1] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); - return \"%*jal\\t%1,%0\"; + return \"%*jal\\t%2,%0\"; } }" [(set_attr "type" "call") @@ -4092,17 +4114,42 @@ move\\t%0,%z4\\n\\ [(parallel [(set (match_operand 0 "register_operand" "=df") (call (match_operand 1 "memory_operand" "m") (match_operand 2 "" "i"))) - (clobber (match_operand 3 "" ""))])] ;; overwrite op3 with $31 + (clobber (reg:SI 31)) + (use (match_operand 3 "" ""))])] ;; next_arg_reg "" " { rtx addr; - operands[3] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); + if (operands[0]) /* eliminate unused code warning */ + { + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[1], 0) = force_reg (FUNCTION_MODE, addr); + + /* In order to pass small structures by value in registers + compatibly with the MIPS compiler, we need to shift the value + into the high part of the register. Function_arg has encoded + a PARALLEL rtx, holding a vector of adjustments to be made + as the next_arg_reg variable, so we split up the insns, + and emit them separately. */ + + if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL) + { + rtvec adjust = XVEC (operands[3], 0); + int num = GET_NUM_ELEM (adjust); + int i; + + for (i = 0; i < num; i++) + emit_insn (RTVEC_ELT (adjust, i)); + } + + emit_call_insn (gen_call_value_internal (operands[0], operands[1], operands[2], + gen_rtx (REG, Pmode, GP_REG_FIRST + 31))); + + DONE; + } - addr = XEXP (operands[1], 0); - if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr)) - XEXP (operands[1], 0) = force_reg (FUNCTION_MODE, addr); }") (define_insn "call_value_internal" @@ -4121,15 +4168,13 @@ move\\t%0,%z4\\n\\ else if (GET_CODE (target) == CONST_INT) { operands[1] = target; - operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); - return \"%*%[li\\t%@,%1\\n\\tjal\\t%2,%@%]\"; + return \"%*%[li\\t%@,%1\\n\\tjal\\t%3,%@%]\"; } else { operands[1] = target; - operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 31); - return \"%*jal\\t%2,%1\"; + return \"%*jal\\t%3,%1\"; } }" [(set_attr "type" "call")