From bb4959a8e67515955d1650c172a8d2bb4326aa85 Mon Sep 17 00:00:00 2001 From: law Date: Wed, 2 Apr 1997 01:33:45 +0000 Subject: [PATCH] * ginclude/stdarg.h: Include va-mn10300.h. * ginclude/varargs.h: Likewise. * ginclude/va-mn10300.h: New file. * mn10300/mn10300.c (expand_prologue): If current_function_varargs is nonzero, then flush d0/d1 back into the stack. (mn10300_builtin_saveregs): New function. (function_arg, function_arg_partial_nregs): New functions. (initial_offset): Tweak now that the RP save area is allocated and deallocated around each call again. * mn10300/mn10300.h (FIRST_PARM_OFFSET): Now 4. (FRAME_POINTER_REQUIRED): Require a frame pointer for all non-leaf functions. (REG_PARM_STACK_SPACE): Now 8 bytes. (FUNCTION_ARG_REGNO_P): Update for new parameter passing conventions. (CUMULATIVE_ARGS, INIT_CUMULATIVE_ARGS): Likewise. (FUNCTION_ARG_ADVANCE, FUNCTION_ARG): Likewise. (FUNCTION_ARG_PARTIAL_NREGS): Likewise. (TRAMPOLINE_TEMPLATE): Don't clobber d0 anymore. (TRAMPOLINE_SIZE, INITIALIZE_TRAMPOLINE): Corresponding changes. (EXPAND_BUILTIN_SAVEREGS): Define. * mn10300/mn10300.md (call, call_value patterns): Allocate and deallocate a stack slot for the return pointer around each call. * mn10300/mn10300.h (RTX_COSTS): Refine. (CASE_VALUES_THRESHHOLD, NO_FUNCTION_CSE): Likewise. * mn10300/mn10300.c (output_tst): New function. * mn10300/mn10300.md (movdi, movdf): Improve code to load constants into registers. (tst insns): Use output_tst to optimize some cases. Add versions to encourage more zero extensions instead of sign extensions of HImode and QImode values. (divsi3, udivsi3): Remove patterns. Replaced by... (divmodsi4, udivmodsi4): New expanders/patterns. (andsi3): Optimize "and" operations with certain constants. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@13827 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/config/mn10300/mn10300.c | 215 +++++++++++++++++++++++++++++++++++++++++- gcc/config/mn10300/mn10300.h | 80 +++++++++------- gcc/config/mn10300/mn10300.md | 178 ++++++++++++++++++++++++++++++---- gcc/ginclude/stdarg.h | 6 +- gcc/ginclude/varargs.h | 6 +- 5 files changed, 427 insertions(+), 58 deletions(-) diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 1e4768ffaa3..5093351870d 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -343,6 +343,20 @@ expand_prologue () { unsigned int size = get_frame_size (); + /* If this is an old-style varargs function, then its arguments + need to be flushed back to the stack. */ + if (current_function_varargs) + { + emit_move_insn (gen_rtx (MEM, SImode, + gen_rtx (PLUS, Pmode, stack_pointer_rtx, + GEN_INT (4))), + gen_rtx (REG, SImode, 0)); + emit_move_insn (gen_rtx (MEM, SImode, + gen_rtx (PLUS, Pmode, stack_pointer_rtx, + GEN_INT (8))), + gen_rtx (REG, SImode, 1)); + } + /* And now store all the registers onto the stack with a single two byte instruction. */ if (regs_ever_live[2] || regs_ever_live[3] @@ -519,9 +533,9 @@ initial_offset (from, to) if (regs_ever_live[2] || regs_ever_live[3] || regs_ever_live[6] || regs_ever_live[7] || frame_pointer_needed) - return 20; + return 16; else - return 4; + return 0; } if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) @@ -529,9 +543,9 @@ initial_offset (from, to) if (regs_ever_live[2] || regs_ever_live[3] || regs_ever_live[6] || regs_ever_live[7] || frame_pointer_needed) - return get_frame_size () + 20; + return get_frame_size () + 16; else - return get_frame_size () + 4; + return get_frame_size (); } if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) @@ -539,3 +553,196 @@ initial_offset (from, to) abort (); } + +/* Flush the argument registers to the stack for a stdarg function; + return the new argument pointer. */ +rtx +mn10300_builtin_saveregs (arglist) + tree arglist; +{ + rtx offset; + tree fntype = TREE_TYPE (current_function_decl); + int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node))) + ? UNITS_PER_WORD : 0); + + if (argadj) + offset = plus_constant (current_function_arg_offset_rtx, argadj); + else + offset = current_function_arg_offset_rtx; + + emit_move_insn (gen_rtx (MEM, SImode, current_function_internal_arg_pointer), + gen_rtx (REG, SImode, 0)); + emit_move_insn (gen_rtx (MEM, SImode, + plus_constant + (current_function_internal_arg_pointer, 4)), + gen_rtx (REG, SImode, 1)); + return copy_to_reg (expand_binop (Pmode, add_optab, + current_function_internal_arg_pointer, + offset, 0, 0, OPTAB_LIB_WIDEN)); +} + +/* Return an RTX to represent where a value with mode MODE will be returned + from a function. If the result is 0, the argument is pushed. */ + +rtx +function_arg (cum, mode, type, named) + CUMULATIVE_ARGS *cum; + enum machine_mode mode; + tree type; + int named; +{ + rtx result = 0; + int size, align; + + /* We only support using 2 data registers as argument registers. */ + int nregs = 2; + + /* Figure out the size of the object to be passed. */ + if (mode == BLKmode) + size = int_size_in_bytes (type); + else + size = GET_MODE_SIZE (mode); + + /* Figure out the alignment of the object to be passed. */ + align = size; + + cum->nbytes = (cum->nbytes + 3) & ~3; + + /* Don't pass this arg via a register if all the argument registers + are used up. */ + if (cum->nbytes > nregs * UNITS_PER_WORD) + return 0; + + /* Don't pass this arg via a register if it would be split between + registers and memory. */ + if (type == NULL_TREE + && cum->nbytes + size > nregs * UNITS_PER_WORD) + return 0; + + switch (cum->nbytes / UNITS_PER_WORD) + { + case 0: + result = gen_rtx (REG, mode, 0); + break; + case 1: + result = gen_rtx (REG, mode, 1); + break; + default: + result = 0; + } + + return result; +} + +/* Return the number of registers to use for an argument passed partially + in registers and partially in memory. */ + +int +function_arg_partial_nregs (cum, mode, type, named) + CUMULATIVE_ARGS *cum; + enum machine_mode mode; + tree type; + int named; +{ + int size, align; + + /* We only support using 2 data registers as argument registers. */ + int nregs = 2; + + /* Figure out the size of the object to be passed. */ + if (mode == BLKmode) + size = int_size_in_bytes (type); + else + size = GET_MODE_SIZE (mode); + + /* Figure out the alignment of the object to be passed. */ + align = size; + + cum->nbytes = (cum->nbytes + 3) & ~3; + + /* Don't pass this arg via a register if all the argument registers + are used up. */ + if (cum->nbytes > nregs * UNITS_PER_WORD) + return 0; + + if (cum->nbytes + size <= nregs * UNITS_PER_WORD) + return 0; + + /* Don't pass this arg via a register if it would be split between + registers and memory. */ + if (type == NULL_TREE + && cum->nbytes + size > nregs * UNITS_PER_WORD) + return 0; + + return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD; +} + +/* Output a tst insn. */ +char * +output_tst (operand, insn) + rtx operand, insn; +{ + + rtx temp; + int past_call = 0; + + /* We can save a byte if we can find a register which has the value + zero in it. */ + temp = PREV_INSN (insn); + while (temp) + { + rtx set; + + /* We allow the search to go through call insns. We record + the fact that we've past a CALL_INSN and reject matches which + use call clobbered registers. */ + if (GET_CODE (temp) == CODE_LABEL + || GET_CODE (temp) == JUMP_INSN + || GET_CODE (temp) == BARRIER) + break; + + if (GET_CODE (temp) == CALL_INSN) + past_call = 1; + + if (GET_CODE (temp) == NOTE) + { + temp = PREV_INSN (temp); + continue; + } + + /* It must be an insn, see if it is a simple set. */ + set = single_set (temp); + if (!set) + { + temp = PREV_INSN (temp); + continue; + } + + /* Are we setting a data register to zero (this does not win for + address registers)? + + If it's a call clobbered register, have we past a call? + + Make sure the register we find isn't the same as ourself; + the mn10300 can't encode that. */ + if (REG_P (SET_DEST (set)) + && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) + && !reg_set_between_p (SET_DEST (set), temp, insn) + && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == DATA_REGS + && REGNO (SET_DEST (set)) != REGNO (operand) + && (!past_call + || !call_used_regs[REGNO (SET_DEST (set))])) + { + rtx xoperands[2]; + xoperands[0] = operand; + xoperands[1] = SET_DEST (set); + + output_asm_insn ("cmp %1,%0", xoperands); + return ""; + } + temp = PREV_INSN (temp); + } + return "cmp 0,%0"; +} diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index 1cac33a1258..f70b6bf6a01 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -351,7 +351,7 @@ enum reg_class { /* Is equal to the size of the saved fp + pc, even if an fp isn't saved since the value is used before we know. */ -#define FIRST_PARM_OFFSET(FNDECL) -4 +#define FIRST_PARM_OFFSET(FNDECL) 4 /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ @@ -404,7 +404,7 @@ enum reg_class { OFFSET = initial_offset (FROM, TO) #define FRAME_POINTER_REQUIRED \ - !(leaf_function_p () || current_function_outgoing_args_size == 0) + !(leaf_function_p ()) #define CAN_DEBUG_WITHOUT_FP @@ -420,21 +420,16 @@ enum reg_class { #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 -/* On the mn10300, the caller is responsible for allocating and deallocating - a stack slot for the "call" and "calls" instructions to save their return - pointer. We used to do this in the "call" and "call_value" expanders, - but that generated poor code. - - Now we pretend that we have an outgoing register parameter space so that - the generic function calling code will allocate the slot. */ - -#define REG_PARM_STACK_SPACE(FNDECL) 4 +/* We use d0/d1 for passing parameters, so allocate 8 bytes of space + for a register flushback area. */ +#define REG_PARM_STACK_SPACE(DECL) 8 #define OUTGOING_REG_PARM_STACK_SPACE /* 1 if N is a possible register number for function argument passing. On the MN10300, no registers are used in this way. */ -#define FUNCTION_ARG_REGNO_P(N) 0 +#define FUNCTION_ARG_REGNO_P(N) ((N) <= 1) + /* Define a data type for recording info about an argument list during the scan of that argument list. This data type should @@ -445,7 +440,8 @@ enum reg_class { On the MN10300, this is a single integer, which is a number of bytes of arguments scanned so far. */ -#define CUMULATIVE_ARGS int +#define CUMULATIVE_ARGS struct cum_arg +struct cum_arg {int nbytes; }; /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. @@ -454,16 +450,16 @@ enum reg_class { On the MN10300, the offset starts at 0. */ #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ - ((CUM) = 0) + ((CUM).nbytes = 0) /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ - ((CUM) += ((MODE) != BLKmode \ - ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ - : (int_size_in_bytes (TYPE) + 3) & ~3)) + ((CUM).nbytes += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, @@ -480,7 +476,12 @@ enum reg_class { /* On the MN10300 all args are pushed. */ -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 +extern struct rtx_def *function_arg (); +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + function_arg (&CUM, MODE, TYPE, NAMED) + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ + function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED) #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ @@ -531,12 +532,11 @@ enum reg_class { #define TRAMPOLINE_TEMPLATE(FILE) \ do { \ fprintf (FILE, "\tadd -4,sp\n"); \ - fprintf (FILE, "\t.long 0x0004fffa\n"); \ + fprintf (FILE, "\t.long 0x0004fffa\n"); \ + fprintf (FILE, "\tmov (0,sp),a0\n"); \ fprintf (FILE, "\tadd 4,sp\n"); \ - fprintf (FILE, "\tmov mdr,d0\n"); \ - fprintf (FILE, "\tmov d0,a0\n"); \ - fprintf (FILE, "\tmov (15,a0),a1\n"); \ - fprintf (FILE, "\tmov (19,a0),a0\n"); \ + fprintf (FILE, "\tmov (13,a0),a1\n"); \ + fprintf (FILE, "\tmov (17,a0),a0\n"); \ fprintf (FILE, "\tjmp (a0)\n"); \ fprintf (FILE, "\t.long 0\n"); \ fprintf (FILE, "\t.long 0\n"); \ @@ -544,7 +544,7 @@ enum reg_class { /* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 0x1d +#define TRAMPOLINE_SIZE 0x1b #define TRAMPOLINE_ALIGNMENT 32 @@ -554,11 +554,18 @@ enum reg_class { #define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ { \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x16)), \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x14)), \ (CXT)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x1a)), \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 0x18)), \ (FNADDR)); \ } +/* Emit code for a call to builtin_saveregs. We must emit USE insns which + reference the 2 integer arg registers. + Ordinarily they are not call used registers, but they are for + _builtin_saveregs, so we must make this explicit. */ + +extern struct rtx_def *mn10300_builtin_saveregs (); +#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) mn10300_builtin_saveregs (ARGLIST) /* Addressing modes, and classification of registers for them. */ @@ -740,22 +747,28 @@ enum reg_class { /* A crude cut at RTX_COSTS for the MN10300. */ /* Provide the costs of a rtl expression. This is in the body of a - switch on CODE. - - There aren't DImode MOD, DIV or MULT operations, so call them - very expensive. Everything else is pretty much a costant cost. */ - + switch on CODE. */ #define RTX_COSTS(RTX,CODE,OUTER_CODE) \ case MOD: \ case DIV: \ - return 60; \ + return 8; \ case MULT: \ - return 20; + return 8; /* Nonzero if access to memory by bytes or half words is no faster than accessing full words. */ #define SLOW_BYTE_ACCESS 1 +/* Dispatch tables on the mn10300 are extremely expensive in terms of code + and readonly data size. So we crank up the case threshold value to + encourage a series of if/else comparisons to implement many small switch + statements. In theory, this value could be increased much more if we + were solely optimizing for space, but we keep it "reasonable" to avoid + serious code efficiency lossage. */ +#define CASE_VALUES_THRESHOLD 6 + +#define NO_FUNCTION_CSE + /* According expr.c, a value of around 6 should minimize code size, and for the MN10300 series, that's our primary concern. */ #define MOVE_RATIO 6 @@ -983,3 +996,4 @@ extern void notice_update_cc (); extern int call_address_operand (); extern enum reg_class secondary_reload_class (); extern int initial_offset (); +extern char *output_tst (); diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index c36ee9e85f7..5db2a944b92 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -185,6 +185,9 @@ || register_operand (operands[1], DImode)" "* { + long val[2]; + REAL_VALUE_TYPE rv; + switch (which_alternative) { case 0: @@ -202,6 +205,26 @@ case 8: case 9: case 10: + if (GET_CODE (operands[1]) == CONST_INT) + { + val[0] = INTVAL (operands[1]); + val[1] = val[0] < 0 ? -1 : 0; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE (operands[1]) == DFmode) + { + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE (rv, val); + } + else if (GET_MODE (operands[1]) == VOIDmode + || GET_MODE (operands[1]) == DImode) + { + val[0] = CONST_DOUBLE_LOW (operands[1]); + val[1] = CONST_DOUBLE_HIGH (operands[1]); + } + } + if (GET_CODE (operands[1]) == MEM && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) { @@ -221,7 +244,24 @@ } else - return \"mov %L1,%L0\;mov %H1,%H0\"; + { + if ((GET_CODE (operands[1]) == CONST_INT + || GET_CODE (operands[1]) == CONST_DOUBLE) + && val[0] == 0 + && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS) + output_asm_insn (\"clr %L0\", operands); + else + output_asm_insn (\"mov %L1,%L0\", operands); + + if ((GET_CODE (operands[1]) == CONST_INT + || GET_CODE (operands[1]) == CONST_DOUBLE) + && val[1] == 0 + && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS) + output_asm_insn (\"clr %H0\", operands); + else + output_asm_insn (\"mov %H1,%H0\", operands); + return \"\"; + } } }" [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) @@ -245,6 +285,9 @@ || register_operand (operands[1], DFmode)" "* { + long val[2]; + REAL_VALUE_TYPE rv; + switch (which_alternative) { case 0: @@ -262,6 +305,26 @@ case 8: case 9: case 10: + if (GET_CODE (operands[1]) == CONST_INT) + { + val[0] = INTVAL (operands[1]); + val[1] = val[0] < 0 ? -1 : 0; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE (operands[1]) == DFmode) + { + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE (rv, val); + } + else if (GET_MODE (operands[1]) == VOIDmode + || GET_MODE (operands[1]) == DImode) + { + val[0] = CONST_DOUBLE_LOW (operands[1]); + val[1] = CONST_DOUBLE_HIGH (operands[1]); + } + } + if (GET_CODE (operands[1]) == MEM && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) { @@ -281,7 +344,24 @@ } else - return \"mov %L1,%L0\;mov %H1,%H0\"; + { + if ((GET_CODE (operands[1]) == CONST_INT + || GET_CODE (operands[1]) == CONST_DOUBLE) + && val[0] == 0 + && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS) + output_asm_insn (\"clr %L0\", operands); + else + output_asm_insn (\"mov %L1,%L0\", operands); + + if ((GET_CODE (operands[1]) == CONST_INT + || GET_CODE (operands[1]) == CONST_DOUBLE) + && val[1] == 0 + && REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS) + output_asm_insn (\"clr %H0\", operands); + else + output_asm_insn (\"mov %H1,%H0\", operands); + return \"\"; + } } }" [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")]) @@ -297,9 +377,22 @@ (define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "da"))] "" - "cmp 0,%0" + "* return output_tst (operands[0], insn);" + [(set_attr "cc" "tst")]) + +(define_insn "" + [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "d")))] + "" + "* return output_tst (operands[0], insn);" + [(set_attr "cc" "tst")]) + +(define_insn "" + [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "d")))] + "" + "* return output_tst (operands[0], insn);" [(set_attr "cc" "tst")]) + (define_insn "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "!*d*a,da") @@ -441,18 +534,12 @@ "mul %2,%0" [(set_attr "cc" "set_zn_c0")]) -(define_insn "divsi3" - [(set (match_operand:SI 0 "register_operand" "=d") - (div:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "register_operand" "d")))] - "" - "ext %0\;div %2,%0" - [(set_attr "cc" "set_zn_c0")]) - -(define_expand "udivsi3" - [(set (match_operand:SI 0 "register_operand" "") - (udiv:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "register_operand" "")))] +(define_expand "udivmodsi4" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (udiv:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (umod:SI (match_dup 1) (match_dup 2)))])] "" " { @@ -462,11 +549,44 @@ }") (define_insn "" - [(set (match_operand:SI 0 "register_operand" "=d") - (udiv:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "register_operand" "d")))] + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "d"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] "" - "divu %2,%0" + "* +{ + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return \"divu %2,%0\"; + else + return \"divu %2,%0\;mov mdr,%3\"; +}" + [(set_attr "cc" "set_zn_c0")]) + +(define_expand "divmodsi4" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (div:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (mod:SI (match_dup 1) (match_dup 2)))])] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "d"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "* +{ + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return \"ext %0\;div %2,%0\"; + else + return \"ext %0\;div %2,%0\;mov mdr,%3\"; +}" [(set_attr "cc" "set_zn_c0")]) (define_insn "clear_mdr" @@ -491,6 +611,22 @@ return \"extbu %0\"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff) return \"exthu %0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff) + return \"add %0,%0\;lsr 1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff) + return \"asl2 %0\;lsr 2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff) + return \"add %0,%0\;asl2 %0\;lsr 3,%0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff) + return \"asl2 %0,%0\;asl2 %0\;lsr 4,%0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe) + return \"lsr 1,%0\;add %0,%0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc) + return \"lsr 2,%0\;asl2 %0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8) + return \"lsr 3,%0\;add %0,%0\;asl2 %0\"; + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0) + return \"lsr 4,%0\;asl2 %0\;asl2 %0\"; return \"and %2,%0\"; }" [(set_attr "cc" "none_0hit,set_zn_c0")]) @@ -826,7 +962,9 @@ { if (! call_address_operand (XEXP (operands[0], 0))) XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0)); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-4))); emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1])); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (4))); DONE; }") @@ -849,9 +987,11 @@ { if (! call_address_operand (XEXP (operands[1], 0))) XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0)); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-4))); emit_call_insn (gen_call_value_internal (operands[0], XEXP (operands[1], 0), operands[2])); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (4))); DONE; }") diff --git a/gcc/ginclude/stdarg.h b/gcc/ginclude/stdarg.h index f817c0b2b78..3b3fdf5cc7f 100644 --- a/gcc/ginclude/stdarg.h +++ b/gcc/ginclude/stdarg.h @@ -44,6 +44,9 @@ #ifdef __sh__ #include "va-sh.h" #else +#ifdef __mn10300__ +#include "va-mn10300.h" +#else /* Define __gnuc_va_list. */ @@ -81,7 +84,7 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */ /* We cast to void * and then to TYPE * because this avoids a warning about increasing the alignment requirement. */ -#if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__) || defined (__mn10300__) +#if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__) /* This is for little-endian machines; small args are padded upward. */ #define va_arg(AP, TYPE) \ (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ @@ -100,6 +103,7 @@ void va_end (__gnuc_va_list); /* Defined in libgcc.a */ #endif /* _STDARG_H */ +#endif /* not mn10300 */ #endif /* not sh */ #endif /* not powerpc with V.4 calling sequence */ #endif /* not h8300 */ diff --git a/gcc/ginclude/varargs.h b/gcc/ginclude/varargs.h index 4f3b8a3a538..c8fa2059deb 100644 --- a/gcc/ginclude/varargs.h +++ b/gcc/ginclude/varargs.h @@ -42,6 +42,9 @@ #ifdef __sh__ #include "va-sh.h" #else +#ifdef __mn10300__ +#include "va-mn10300.h" +#else #ifdef __NeXT__ @@ -100,7 +103,7 @@ typedef void *__gnuc_va_list; (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) #endif -#if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__) || defined (__mn10300__) +#if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__) /* This is for little-endian machines; small args are padded upward. */ #define va_arg(AP, TYPE) \ (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ @@ -117,6 +120,7 @@ typedef void *__gnuc_va_list; /* Copy __gnuc_va_list into another variable of this type. */ #define __va_copy(dest, src) (dest) = (src) +#endif /* not mn10300 */ #endif /* not sh */ #endif /* not powerpc with V.4 calling sequence */ #endif /* not h8300 */ -- 2.11.4.GIT