Commit 22ef4e9b by Jeff Law

stdarg.h: Include va-mn10300.h.

        * 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.

From-SVN: r13827
parent e8adce17
......@@ -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";
}
......@@ -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 ();
......@@ -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;
}")
......
......@@ -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 */
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment