#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "expr.h"
#include "function.h"
#include "obstack.h"
#include "ggc.h"
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
rtx zero_dreg;
rtx zero_areg;
static void count_tst_insns PARAMS ((int *));
static int out_of_line_epilogue;
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
struct gcc_target targetm = TARGET_INITIALIZER;
void
asm_file_start (file)
FILE *file;
{
fprintf (file, "#\tGCC For the Matsushita MN10200\n");
if (optimize)
fprintf (file, "# -O%d\n", optimize);
else
fprintf (file, "\n\n");
output_file_directive (file, main_input_filename);
ggc_add_rtx_root (&zero_dreg, 1);
ggc_add_rtx_root (&zero_areg, 1);
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
switch (code)
{
case 'b':
case 'B':
switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
{
case NE:
fprintf (file, "ne");
break;
case EQ:
fprintf (file, "eq");
break;
case GE:
fprintf (file, "ge");
break;
case GT:
fprintf (file, "gt");
break;
case LE:
fprintf (file, "le");
break;
case LT:
fprintf (file, "lt");
break;
case GEU:
fprintf (file, "cc");
break;
case GTU:
fprintf (file, "hi");
break;
case LEU:
fprintf (file, "ls");
break;
case LTU:
fprintf (file, "cs");
break;
default:
abort ();
}
break;
case 'C':
if (GET_CODE (x) == REG)
{
fputc ('(', file);
print_operand (file, x, 0);
fputc (')', file);
}
else
print_operand (file, x, 0);
break;
case 'L':
case 'o':
switch (GET_CODE (x))
{
case MEM:
fputc ('(', file);
output_address (XEXP (x, 0));
fputc (')', file);
break;
case REG:
fprintf (file, "%s", reg_names[REGNO (x)]);
break;
case SUBREG:
fprintf (file, "%s", reg_names[subreg_regno (x)]);
break;
case CONST_DOUBLE:
if (code == 'L')
{
long val;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
print_operand_address (file, GEN_INT (val & 0xffff));
}
else
{
long val;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
val &= 0xffff;
val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000;
print_operand_address (file, GEN_INT (val));
}
break;
case CONST_INT:
if (code == 'L')
print_operand_address (file, GEN_INT ((INTVAL (x) & 0xffff)));
else
{
unsigned int val = INTVAL (x) & 0xffff;
val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000;
print_operand_address (file, GEN_INT (val));
}
break;
default:
abort ();
}
break;
case 'H':
case 'h':
switch (GET_CODE (x))
{
case MEM:
fputc ('(', file);
x = adjust_address (x, HImode, 2);
output_address (XEXP (x, 0));
fputc (')', file);
break;
case REG:
fprintf (file, "%s", reg_names[REGNO (x) + 1]);
break;
case SUBREG:
fprintf (file, "%s", reg_names[subreg_regno (x) + 1]);
break;
case CONST_DOUBLE:
if (code == 'H')
{
long val;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
print_operand_address (file, GEN_INT ((val >> 16) & 0xffff));
}
else
{
long val;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
val = (val >> 16) & 0xffff;
val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000;
print_operand_address (file, GEN_INT (val));
}
break;
case CONST_INT:
if (code == 'H')
print_operand_address (file,
GEN_INT ((INTVAL (x) >> 16) & 0xffff));
else
{
unsigned int val = (INTVAL (x) >> 16) & 0xffff;
val = (((val) & 0xffff) ^ (~0x7fff)) + 0x8000;
print_operand_address (file, GEN_INT (val));
}
break;
default:
abort ();
}
break;
case 'N':
if (GET_CODE (x) != CONST_INT)
abort ();
fprintf (file, "%d", ~INTVAL (x));
break;
case 'A':
if (GET_CODE (x) != MEM)
abort ();
if (GET_CODE (XEXP (x, 0)) == REG)
x = gen_rtx_PLUS (PSImode, XEXP (x, 0), GEN_INT (0));
else
x = XEXP (x, 0);
fputc ('(', file);
output_address (x);
fputc (')', file);
break;
case 'Z':
print_operand (file, XEXP (x, 1), 0);
break;
case 's':
case 'S':
if (GET_CODE (x) == CONST_INT)
{
int val = INTVAL (x);
if (code == 's')
x = GEN_INT (((val & 0xffff) ^ (~0x7fff)) + 0x8000);
else
x = GEN_INT (((val & 0xff) ^ (~0x7f)) + 0x80);
}
default:
switch (GET_CODE (x))
{
case MEM:
fputc ('(', file);
output_address (XEXP (x, 0));
fputc (')', file);
break;
case REG:
fprintf (file, "%s", reg_names[REGNO (x)]);
break;
case SUBREG:
fprintf (file, "%s", reg_names[subreg_regno (x)]);
break;
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
case CODE_LABEL:
print_operand_address (file, x);
break;
default:
abort ();
}
break;
}
}
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
switch (GET_CODE (addr))
{
case REG:
print_operand (file, addr, 0);
break;
case PLUS:
{
rtx base, index;
if (REG_P (XEXP (addr, 0))
&& REG_OK_FOR_BASE_P (XEXP (addr, 0)))
base = XEXP (addr, 0), index = XEXP (addr, 1);
else if (REG_P (XEXP (addr, 1))
&& REG_OK_FOR_BASE_P (XEXP (addr, 1)))
base = XEXP (addr, 1), index = XEXP (addr, 0);
else
abort ();
print_operand (file, index, 0);
fputc (',', file);
print_operand (file, base, 0);;
break;
}
case SYMBOL_REF:
output_addr_const (file, addr);
break;
default:
output_addr_const (file, addr);
break;
}
}
static void
count_tst_insns (areg_countp)
int *areg_countp;
{
rtx insn;
*areg_countp = 0;
if (!optimize)
return;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx pat;
if (GET_CODE (insn) != INSN)
continue;
pat = PATTERN (insn);
if (GET_CODE (pat) != SET)
continue;
if (SET_DEST (pat) == cc0_rtx
&& GET_CODE (SET_SRC (pat)) == REG
&& REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS)
(*areg_countp)++;
}
}
int
total_frame_size ()
{
unsigned int size = get_frame_size ();
unsigned int outgoing_args_size = current_function_outgoing_args_size;
int i;
if (optimize && !current_function_needs_context && !frame_pointer_needed)
{
int inline_count, outline_count;
inline_count = 0;
if (regs_ever_live[5])
inline_count += 2;
if (regs_ever_live[6])
inline_count += 2;
if (regs_ever_live[2])
inline_count += 3;
if (regs_ever_live[3])
inline_count += 3;
if (size || outgoing_args_size
|| regs_ever_live[5] || regs_ever_live[6]
|| regs_ever_live[2] || regs_ever_live[3])
inline_count += 2;
inline_count = inline_count * 2 + 1;
outline_count = 3;
outline_count += (outgoing_args_size == 0 ? 0 : 2);
if (get_frame_size () != 0)
outline_count += 2;
outline_count = outline_count * 2 + 1;
if (get_frame_size () == 0 && outgoing_args_size == 0)
outline_count -= 1;
if (inline_count > outline_count)
return size + outgoing_args_size + 16;
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if ((regs_ever_live[i] && !call_used_regs[i] && ! fixed_regs[i])
|| (i == FRAME_POINTER_REGNUM && frame_pointer_needed))
size += 4;
}
return (size + outgoing_args_size);
}
void
expand_prologue ()
{
unsigned int size = total_frame_size ();
unsigned int outgoing_args_size = current_function_outgoing_args_size;
int offset, i;
zero_areg = NULL_RTX;
zero_dreg = NULL_RTX;
if (optimize && !current_function_needs_context && !frame_pointer_needed)
{
int inline_count, outline_count, areg_count;
end_sequence ();
count_tst_insns (&areg_count);
start_sequence ();
inline_count = 0;
if (regs_ever_live[5])
inline_count += 2;
if (regs_ever_live[6])
inline_count += 2;
if (regs_ever_live[2])
inline_count += 3;
if (regs_ever_live[3])
inline_count += 3;
if (size || outgoing_args_size
|| regs_ever_live[5] || regs_ever_live[6]
|| regs_ever_live[2] || regs_ever_live[3])
inline_count += 2;
inline_count = inline_count * 2 + 1;
outline_count = 3;
outline_count += (outgoing_args_size == 0 ? 0 : 2);
if (get_frame_size () != 0)
outline_count += 2;
outline_count = outline_count * 2 + 1;
if (get_frame_size () == 0 && outgoing_args_size == 0)
outline_count -= 1;
if (inline_count > outline_count)
{
if (get_frame_size () != 0)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-size + outgoing_args_size + 16)));
emit_insn (gen_outline_prologue_call ());
if (outgoing_args_size)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-outgoing_args_size)));
out_of_line_epilogue = 1;
if (areg_count > 1
&& (!regs_ever_live[2] || !regs_ever_live[3]))
{
if (!regs_ever_live[2])
{
regs_ever_live[2] = 1;
zero_dreg = gen_rtx_REG (HImode, 2);
}
if (!regs_ever_live[3])
{
regs_ever_live[3] = 1;
zero_dreg = gen_rtx_REG (HImode, 3);
}
}
if (zero_dreg == NULL_RTX
&& areg_count > 2
&& (!regs_ever_live[5] || !regs_ever_live[6]))
{
if (!regs_ever_live[5])
{
regs_ever_live[5] = 1;
zero_areg = gen_rtx_REG (HImode, 5);
}
if (!regs_ever_live[6])
{
regs_ever_live[6] = 1;
zero_areg = gen_rtx_REG (HImode, 6);
}
}
if (zero_dreg)
emit_move_insn (zero_dreg, const0_rtx);
if (zero_areg)
emit_move_insn (zero_areg, const0_rtx);
return;
}
}
out_of_line_epilogue = 0;
if (current_function_needs_context)
{
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-4)));
emit_move_insn (gen_rtx_MEM (PSImode, stack_pointer_rtx),
gen_rtx_REG (PSImode, STATIC_CHAIN_REGNUM));
}
if (frame_pointer_needed)
{
emit_move_insn (gen_rtx_REG (PSImode, 4), frame_pointer_rtx);
emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
}
if (size)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-size)));
for (i = 0, offset = outgoing_args_size;
i < FIRST_PSEUDO_REGISTER; i++)
{
if ((regs_ever_live[i] && !call_used_regs[i] && ! fixed_regs[i])
|| (i == FRAME_POINTER_REGNUM && frame_pointer_needed))
{
int regno;
regno = (i == FRAME_POINTER_REGNUM && frame_pointer_needed) ? 4 : i;
emit_move_insn (gen_rtx_MEM (PSImode,
plus_constant (stack_pointer_rtx,
offset)),
gen_rtx_REG (PSImode, regno));
offset += 4;
}
}
if (current_function_needs_context)
{
emit_move_insn (gen_rtx_REG (PSImode, STATIC_CHAIN_REGNUM),
gen_rtx (MEM, PSImode,
gen_rtx_PLUS (PSImode, stack_pointer_rtx,
GEN_INT (size))));
}
}
void
expand_epilogue ()
{
unsigned int size;
unsigned int outgoing_args_size = current_function_outgoing_args_size;
int offset, i, temp_regno;
rtx basereg;
size = total_frame_size ();
if (DECL_RESULT (current_function_decl)
&& DECL_RTL (DECL_RESULT (current_function_decl))
&& REG_P (DECL_RTL (DECL_RESULT (current_function_decl))))
temp_regno = (REGNO (DECL_RTL (DECL_RESULT (current_function_decl))) == 4
? 0 : 4);
else
temp_regno = 4;
if (out_of_line_epilogue)
{
if (get_frame_size () == 0 && outgoing_args_size == 0)
{
emit_jump_insn (gen_outline_epilogue_jump ());
return;
}
if (outgoing_args_size)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (outgoing_args_size)));
if (temp_regno == 0)
emit_insn (gen_outline_epilogue_call_d0 ());
else if (temp_regno == 4)
emit_insn (gen_outline_epilogue_call_a0 ());
if (get_frame_size () != 0)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (size - outgoing_args_size - 16)));
emit_jump_insn (gen_return_internal ());
return;
}
if (frame_pointer_needed)
{
basereg = frame_pointer_rtx;
offset = -(size - outgoing_args_size);
}
else
{
basereg = stack_pointer_rtx;
offset = outgoing_args_size;
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if ((regs_ever_live[i] && !call_used_regs[i] && ! fixed_regs[i])
|| (i == FRAME_POINTER_REGNUM && frame_pointer_needed))
{
int regno;
regno = ((i == FRAME_POINTER_REGNUM && frame_pointer_needed)
? temp_regno : i);
emit_move_insn (gen_rtx_REG (PSImode, regno),
gen_rtx_MEM (PSImode,
plus_constant (basereg, offset)));
offset += 4;
}
}
if (frame_pointer_needed)
{
emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
emit_move_insn (frame_pointer_rtx, gen_rtx_REG (PSImode, temp_regno));
}
else if (size)
{
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (size)));
}
if (current_function_needs_context)
emit_insn (gen_addpsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (4)));
if (size == 0 && !current_function_needs_context)
emit_jump_insn (gen_return ());
else
emit_jump_insn (gen_return_internal ());
}
void
notice_update_cc (body, insn)
rtx body;
rtx insn;
{
switch (get_attr_cc (insn))
{
case CC_NONE:
break;
case CC_NONE_0HIT:
if (cc_status.value1 != 0
&& reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
cc_status.value1 = 0;
break;
case CC_SET_ZN:
CC_STATUS_INIT;
cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
cc_status.value1 = recog_data.operand[0];
break;
case CC_SET_ZNV:
CC_STATUS_INIT;
cc_status.flags |= CC_NO_CARRY;
cc_status.value1 = recog_data.operand[0];
break;
case CC_COMPARE:
CC_STATUS_INIT;
cc_status.value1 = SET_SRC (body);
break;
case CC_CLOBBER:
CC_STATUS_INIT;
break;
default:
CC_STATUS_INIT;
break;
}
}
int
call_address_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
}
int
constant_memory_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == MEM && CONSTANT_ADDRESS_P (XEXP (op, 0));
}
int
psimode_truncation_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (general_operand (op, mode)
&& (GET_CODE (op) != MEM
|| memory_address_p (PSImode, XEXP (op, 0))));
}
enum reg_class
secondary_reload_class (class, mode, in, input)
enum reg_class class;
enum machine_mode mode;
rtx in;
int input;
{
if (input
&& GET_CODE (in) == MEM
&& (mode == QImode)
&& class == ADDRESS_REGS)
return DATA_REGS;
if (! input
&& GET_CODE (in) == MEM
&& (mode != PSImode)
&& class == ADDRESS_REGS)
return DATA_REGS;
return NO_REGS;
}
int
nshift_operator (x, mode)
rtx x;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (x))
{
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
return 1;
default:
return 0;
}
}
int
expand_a_shift (mode, code, operands)
enum machine_mode mode;
int code;
rtx operands[];
{
emit_move_insn (operands[0], operands[1]);
emit_insn (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2,
gen_rtx_SET (VOIDmode, operands[0],
gen_rtx (code, mode,
operands[0], operands[2])),
gen_rtx_CLOBBER (VOIDmode,
gen_rtx_SCRATCH (HImode)))));
return 1;
}
enum shift_alg
{
SHIFT_INLINE,
SHIFT_SPECIAL,
SHIFT_LOOP,
SHIFT_MAX
};
enum shift_type
{
SHIFT_ASHIFT, SHIFT_LSHIFTRT, SHIFT_ASHIFTRT
};
enum shift_mode
{
HIshift
};
struct shift_insn
{
const char *assembler;
int cc_valid;
};
static const struct shift_insn shift_one[3][3] =
{
{
{ "add\t%0,%0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
},
{
{ "lsr\t%0", CC_NO_CARRY },
},
{
{ "asr\t%0", CC_NO_CARRY },
},
};
static enum shift_alg get_shift_alg PARAMS ((enum shift_type,
enum machine_mode, int,
const char **, int *));
static enum shift_alg
get_shift_alg (shift_type, mode, count, assembler_p, cc_valid_p)
enum shift_type shift_type;
enum machine_mode mode;
int count;
const char **assembler_p;
int *cc_valid_p;
{
enum shift_alg alg = SHIFT_LOOP;
enum shift_mode shift_mode;
if (count < 0 || count > GET_MODE_BITSIZE (mode))
abort ();
switch (mode)
{
case HImode:
shift_mode = HIshift;
break;
default:
abort ();
}
*assembler_p = shift_one[shift_type][shift_mode].assembler;
*cc_valid_p = shift_one[shift_type][shift_mode].cc_valid;
switch (shift_mode)
{
case HIshift:
if (count <= 4)
return SHIFT_INLINE;
else if (count < 15 && shift_type != SHIFT_ASHIFTRT)
{
switch (count)
{
case 5:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 32,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 32,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 6:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 64,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 64,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 7:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 128,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 128,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 8:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 256,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 256,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 9:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 512,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 512,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 10:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 1024,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 1024,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 11:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 2048,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 2048,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 12:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 4096,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 4096,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 13:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 8192,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 8192,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
case 14:
if (shift_type == SHIFT_ASHIFT)
*assembler_p = "mov 16384,%4\n\tmul %4,%0";
else if (shift_type == SHIFT_LSHIFTRT)
*assembler_p
= "sub %4,%4\n\tmov %4,mdr\n\tmov 16384,%4\n\tdivu %4,%0";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
}
}
else if (count == 15)
{
if (shift_type == SHIFT_ASHIFTRT)
{
*assembler_p = "add\t%0,%0\n\tsubc\t%0,%0\n";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
}
if (shift_type == SHIFT_LSHIFTRT)
{
*assembler_p = "add\t%0,%0\n\tmov 0,%0\n\trol %0\n";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
}
if (shift_type == SHIFT_ASHIFT)
{
*assembler_p = "ror\t%0\n\tmov 0,%0\n\tror %0\n";
*cc_valid_p = CC_NO_CARRY;
return SHIFT_SPECIAL;
}
}
break;
default:
abort ();
}
return alg;
}
const char *
emit_a_shift (insn, operands)
rtx insn ATTRIBUTE_UNUSED;
rtx *operands;
{
static int loopend_lab;
const char *assembler;
int cc_valid;
rtx shift = operands[3];
enum machine_mode mode = GET_MODE (shift);
enum rtx_code code = GET_CODE (shift);
enum shift_type shift_type;
enum shift_mode shift_mode;
loopend_lab++;
switch (mode)
{
case HImode:
shift_mode = HIshift;
break;
default:
abort ();
}
switch (code)
{
case ASHIFTRT:
shift_type = SHIFT_ASHIFTRT;
break;
case LSHIFTRT:
shift_type = SHIFT_LSHIFTRT;
break;
case ASHIFT:
shift_type = SHIFT_ASHIFT;
break;
default:
abort ();
}
if (GET_CODE (operands[2]) != CONST_INT)
{
output_asm_insn ("mov %2,%4", operands);
output_asm_insn ("cmp 0,%4", operands);
fprintf (asm_out_file, "\tble .Lle%d\n", loopend_lab);
get_shift_alg (shift_type, mode, 1, &assembler, &cc_valid);
}
else
{
int n = INTVAL (operands[2]);
enum shift_alg alg;
if (n < 0)
n = 0;
else if (n > GET_MODE_BITSIZE (mode))
n = GET_MODE_BITSIZE (mode);
alg = get_shift_alg (shift_type, mode, n, &assembler, &cc_valid);
switch (alg)
{
case SHIFT_INLINE:
while (n > 0)
{
output_asm_insn (assembler, operands);
n -= 1;
}
if (cc_valid)
{
cc_status.value1 = operands[0];
cc_status.flags |= cc_valid;
}
return "";
case SHIFT_SPECIAL:
output_asm_insn (assembler, operands);
if (cc_valid)
{
cc_status.value1 = operands[0];
cc_status.flags |= cc_valid;
}
return "";
}
{
fprintf (asm_out_file, "\tmov %d,%s\n", n,
reg_names[REGNO (operands[4])]);
fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
output_asm_insn (assembler, operands);
output_asm_insn ("add -1,%4", operands);
fprintf (asm_out_file, "\tbne .Llt%d\n", loopend_lab);
return "";
}
}
fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
output_asm_insn (assembler, operands);
output_asm_insn ("add -1,%4", operands);
fprintf (asm_out_file, "\tbne .Llt%d\n", loopend_lab);
fprintf (asm_out_file, ".Lle%d:\n", loopend_lab);
return "";
}
rtx
function_arg (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
rtx result = 0;
int size, align;
int nregs = 2;
if (!named)
return NULL_RTX;
if (mode == BLKmode)
size = int_size_in_bytes (type);
else if (mode == PSImode)
size = 2;
else
size = GET_MODE_SIZE (mode);
align = size;
cum->nbytes = (cum->nbytes + 1) & ~1;
if (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;
}
int
function_arg_partial_nregs (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int size, align;
int nregs = 2;
return 0;
if (!named)
return 0;
if (mode == BLKmode)
size = int_size_in_bytes (type);
else if (mode == PSImode)
size = 2;
else
size = GET_MODE_SIZE (mode);
align = size;
cum->nbytes = (cum->nbytes + 1) & ~1;
if (cum->nbytes > nregs * UNITS_PER_WORD)
return 0;
if (cum->nbytes + size <= nregs * UNITS_PER_WORD)
return 0;
if (type == NULL_TREE
&& cum->nbytes + size > nregs * UNITS_PER_WORD)
return 0;
return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;
}
rtx
mn10200_va_arg (valist, type)
tree valist, type;
{
HOST_WIDE_INT align, rsize;
tree t, ptr, pptr;
align = PARM_BOUNDARY / BITS_PER_UNIT;
rsize = (((int_size_in_bytes (type) + align - 1) / align) * align);
t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
build_int_2 ((rsize > 8 ? 4 : rsize), 0));
TREE_SIDE_EFFECTS (t) = 1;
ptr = build_pointer_type (type);
if (rsize > 8)
{
pptr = build_pointer_type (ptr);
t = build1 (NOP_EXPR, pptr, t);
TREE_SIDE_EFFECTS (t) = 1;
t = build1 (INDIRECT_REF, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
else
{
t = build1 (NOP_EXPR, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
return force_reg (Pmode, expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL));
}
const char *
output_tst (operand, insn)
rtx operand, insn;
{
rtx temp;
int past_call = 0;
if (REGNO_REG_CLASS (REGNO (operand)) != ADDRESS_REGS)
return "cmp 0,%0";
if (zero_dreg || zero_areg)
{
rtx xoperands[2];
xoperands[0] = operand;
xoperands[1] = zero_dreg ? zero_dreg : zero_areg;
output_asm_insn ("cmp %1,%0", xoperands);
return "";
}
temp = PREV_INSN (insn);
while (temp)
{
rtx set;
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;
}
set = single_set (temp);
if (!set)
{
temp = PREV_INSN (temp);
continue;
}
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)
&& (!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";
}
int
extendpsi_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (general_operand (op, mode)
|| (GET_CODE (op) == PLUS
&& XEXP (op, 0) == stack_pointer_rtx
&& general_operand (XEXP (op, 1), VOIDmode)));
}