#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.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 "function.h"
#include "expr.h"
#include "recog.h"
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
int arc_cpu_type;
const char *arc_mangle_cpu;
rtx arc_compare_op0, arc_compare_op1;
const char *arc_text_section;
const char *arc_data_section;
const char *arc_rodata_section;
char arc_punct_chars[256];
static int arc_ccfsm_state;
static int arc_ccfsm_current_cc;
static rtx arc_ccfsm_target_insn;
static int arc_ccfsm_target_label;
#define MAX_INSNS_SKIPPED 3
static int last_insn_set_cc_p;
static int current_insn_set_cc_p;
static bool arc_handle_option (size_t, const char *, int);
static void record_cc_ref (rtx);
static void arc_init_reg_tables (void);
static int get_arc_condition_code (rtx);
const struct attribute_spec arc_attribute_table[];
static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
static bool arc_assemble_integer (rtx, unsigned int, int);
static void arc_output_function_prologue (FILE *, HOST_WIDE_INT);
static void arc_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void arc_file_start (void);
static void arc_internal_label (FILE *, const char *, unsigned long);
static void arc_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
tree, int *, int);
static bool arc_rtx_costs (rtx, int, int, int *);
static int arc_address_cost (rtx);
static void arc_external_libcall (rtx);
static bool arc_return_in_memory (tree, tree);
static bool arc_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER arc_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue
#undef TARGET_ASM_FILE_START
#define TARGET_ASM_FILE_START arc_file_start
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE arc_attribute_table
#undef TARGET_ASM_INTERNAL_LABEL
#define TARGET_ASM_INTERNAL_LABEL arc_internal_label
#undef TARGET_ASM_EXTERNAL_LIBCALL
#define TARGET_ASM_EXTERNAL_LIBCALL arc_external_libcall
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION arc_handle_option
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS arc_rtx_costs
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST arc_address_cost
#undef TARGET_PROMOTE_FUNCTION_ARGS
#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
#undef TARGET_PROMOTE_FUNCTION_RETURN
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY arc_return_in_memory
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE arc_pass_by_reference
#undef TARGET_CALLEE_COPIES
#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS arc_setup_incoming_varargs
struct gcc_target targetm = TARGET_INITIALIZER;
static bool
arc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
{
switch (code)
{
case OPT_mcpu_:
return strcmp (arg, "base") == 0 || ARC_EXTENSION_CPU (arg);
default:
return true;
}
}
void
arc_init (void)
{
char *tmp;
arc_text_section = tmp = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string);
arc_data_section = tmp = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string);
arc_rodata_section = tmp = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string);
arc_init_reg_tables ();
memset (arc_punct_chars, 0, sizeof (arc_punct_chars));
arc_punct_chars['#'] = 1;
arc_punct_chars['*'] = 1;
arc_punct_chars['?'] = 1;
arc_punct_chars['!'] = 1;
arc_punct_chars['~'] = 1;
}
static const char *const arc_condition_codes[] =
{
"al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv",
"gt", "le", "ge", "lt", "hi", "ls", "pnz", 0
};
#define ARC_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
static int
get_arc_condition_code (rtx comparison)
{
switch (GET_CODE (comparison))
{
case EQ : return 2;
case NE : return 3;
case GT : return 10;
case LE : return 11;
case GE : return 12;
case LT : return 13;
case GTU : return 14;
case LEU : return 15;
case LTU : return 6;
case GEU : return 7;
default : gcc_unreachable ();
}
return (42);
}
enum machine_mode
arc_select_cc_mode (enum rtx_code op,
rtx x ATTRIBUTE_UNUSED,
rtx y ATTRIBUTE_UNUSED)
{
switch (op)
{
case EQ :
case NE :
return CCZNmode;
default :
switch (GET_CODE (x))
{
case AND :
case IOR :
case XOR :
case SIGN_EXTEND :
case ZERO_EXTEND :
return CCZNmode;
case ASHIFT :
case ASHIFTRT :
case LSHIFTRT :
return CCZNCmode;
default:
break;
}
}
return CCmode;
}
enum arc_mode_class {
C_MODE,
S_MODE, D_MODE, T_MODE, O_MODE,
SF_MODE, DF_MODE, TF_MODE, OF_MODE
};
#define C_MODES (1 << (int) C_MODE)
#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
const unsigned int arc_hard_regno_mode_ok[] = {
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES,
D_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, C_MODES
};
unsigned int arc_mode_class [NUM_MACHINE_MODES];
enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER];
static void
arc_init_reg_tables (void)
{
int i;
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
switch (GET_MODE_CLASS (i))
{
case MODE_INT:
case MODE_PARTIAL_INT:
case MODE_COMPLEX_INT:
if (GET_MODE_SIZE (i) <= 4)
arc_mode_class[i] = 1 << (int) S_MODE;
else if (GET_MODE_SIZE (i) == 8)
arc_mode_class[i] = 1 << (int) D_MODE;
else if (GET_MODE_SIZE (i) == 16)
arc_mode_class[i] = 1 << (int) T_MODE;
else if (GET_MODE_SIZE (i) == 32)
arc_mode_class[i] = 1 << (int) O_MODE;
else
arc_mode_class[i] = 0;
break;
case MODE_FLOAT:
case MODE_COMPLEX_FLOAT:
if (GET_MODE_SIZE (i) <= 4)
arc_mode_class[i] = 1 << (int) SF_MODE;
else if (GET_MODE_SIZE (i) == 8)
arc_mode_class[i] = 1 << (int) DF_MODE;
else if (GET_MODE_SIZE (i) == 16)
arc_mode_class[i] = 1 << (int) TF_MODE;
else if (GET_MODE_SIZE (i) == 32)
arc_mode_class[i] = 1 << (int) OF_MODE;
else
arc_mode_class[i] = 0;
break;
case MODE_CC:
arc_mode_class[i] = 1 << (int) C_MODE;
break;
default:
arc_mode_class[i] = 0;
break;
}
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (i < 60)
arc_regno_reg_class[i] = GENERAL_REGS;
else if (i == 60)
arc_regno_reg_class[i] = LPCOUNT_REG;
else if (i == 61)
arc_regno_reg_class[i] = NO_REGS ;
else
arc_regno_reg_class[i] = NO_REGS;
}
}
const struct attribute_spec arc_attribute_table[] =
{
{ "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
static tree
arc_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
tree name,
tree args,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
tree value = TREE_VALUE (args);
if (TREE_CODE (value) != STRING_CST)
{
warning (OPT_Wattributes,
"argument of %qs attribute is not a string constant",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
&& strcmp (TREE_STRING_POINTER (value), "ilink2"))
{
warning (OPT_Wattributes,
"argument of %qs attribute is not \"ilink1\" or \"ilink2\"",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
int
call_address_operand (rtx op, enum machine_mode mode)
{
return (symbolic_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && LEGITIMATE_CONSTANT_P (op))
|| (GET_CODE (op) == REG));
}
int
call_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return call_address_operand (op, mode);
}
int
symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
case CONST :
return 1;
default:
return 0;
}
}
int
symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == LABEL_REF);
}
int
short_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return 0;
return SMALL_INT (INTVAL (op));
}
int
long_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case SYMBOL_REF :
case LABEL_REF :
case CONST :
return 1;
case CONST_INT :
return !SMALL_INT (INTVAL (op));
case CONST_DOUBLE :
return 1;
default:
break;
}
return 0;
}
int
long_immediate_loadstore_operand (rtx op,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
switch (GET_CODE (op))
{
case SYMBOL_REF :
case LABEL_REF :
case CONST :
return 1;
case CONST_INT :
return 1;
case CONST_DOUBLE :
return 1;
case REG :
return 0;
case PLUS :
if (GET_CODE (XEXP (op, 1)) == CONST_INT
&& !SMALL_INT (INTVAL (XEXP (op, 1))))
return 1;
return 0;
default:
break;
}
return 0;
}
int
move_src_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
case SYMBOL_REF :
case LABEL_REF :
case CONST :
return 1;
case CONST_INT :
return (LARGE_INT (INTVAL (op)));
case CONST_DOUBLE :
if (mode == SImode)
return arc_double_limm_p (op);
if (mode == SFmode)
return GET_MODE (op) == SFmode;
return 0;
case REG :
return register_operand (op, mode);
case SUBREG :
if (GET_CODE (SUBREG_REG (op)) == MEM)
return address_operand (XEXP (SUBREG_REG (op), 0), mode);
else
return register_operand (op, mode);
case MEM :
return address_operand (XEXP (op, 0), mode);
default :
return 0;
}
}
int
move_double_src_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
case REG :
return register_operand (op, mode);
case SUBREG :
if (GET_CODE (SUBREG_REG (op)) == MEM)
return move_double_src_operand (SUBREG_REG (op), mode);
else
return register_operand (op, mode);
case MEM :
if (GET_CODE (XEXP (op, 0)) == PRE_DEC
|| GET_CODE (XEXP (op, 0)) == PRE_INC)
return 0;
return address_operand (XEXP (op, 0), mode);
case CONST_INT :
case CONST_DOUBLE :
return 1;
default :
return 0;
}
}
int
move_dest_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
case REG :
return register_operand (op, mode);
case SUBREG :
if (GET_CODE (SUBREG_REG (op)) == MEM)
return address_operand (XEXP (SUBREG_REG (op), 0), mode);
else
return register_operand (op, mode);
case MEM :
return address_operand (XEXP (op, 0), mode);
default :
return 0;
}
}
int
load_update_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM
|| GET_MODE (op) != mode)
return 0;
op = XEXP (op, 0);
if (GET_CODE (op) != PLUS
|| GET_MODE (op) != Pmode
|| !register_operand (XEXP (op, 0), Pmode)
|| !nonmemory_operand (XEXP (op, 1), Pmode))
return 0;
return 1;
}
int
store_update_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM
|| GET_MODE (op) != mode)
return 0;
op = XEXP (op, 0);
if (GET_CODE (op) != PLUS
|| GET_MODE (op) != Pmode
|| !register_operand (XEXP (op, 0), Pmode)
|| !(GET_CODE (XEXP (op, 1)) == CONST_INT
&& SMALL_INT (INTVAL (XEXP (op, 1)))))
return 0;
return 1;
}
int
nonvol_nonimm_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
return 0;
return nonimmediate_operand (op, mode);
}
int
const_sint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
}
int
const_uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if HOST_BITS_PER_WIDE_INT > 32
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL));
#else
return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0)
|| (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));
#endif
}
int
proper_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code;
if (!COMPARISON_P (op))
return 0;
code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CCZNmode)
return (code == EQ || code == NE);
if (GET_MODE (XEXP (op, 0)) == CCZNCmode)
return (code == EQ || code == NE
|| code == LTU || code == GEU || code == GTU || code == LEU);
return 1;
}
rtx
gen_compare_reg (enum rtx_code code, rtx x, rtx y)
{
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
rtx cc_reg;
cc_reg = gen_rtx_REG (mode, 61);
emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
gen_rtx_COMPARE (mode, x, y)));
return cc_reg;
}
int
arc_double_limm_p (rtx value)
{
HOST_WIDE_INT low, high;
gcc_assert (GET_CODE (value) == CONST_DOUBLE);
low = CONST_DOUBLE_LOW (value);
high = CONST_DOUBLE_HIGH (value);
if (low & 0x80000000)
{
return (((unsigned HOST_WIDE_INT) low <= 0xffffffff && high == 0)
|| (((low & - (unsigned HOST_WIDE_INT) 0x80000000)
== - (unsigned HOST_WIDE_INT) 0x80000000)
&& high == -1));
}
else
{
return (unsigned HOST_WIDE_INT) low <= 0x7fffffff && high == 0;
}
}
static void
arc_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
tree type ATTRIBUTE_UNUSED,
int *pretend_size,
int no_rtl)
{
int first_anon_arg;
gcc_assert (mode != BLKmode);
first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
/ UNITS_PER_WORD);
if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl)
{
int first_reg_offset = first_anon_arg;
int size = MAX_ARC_PARM_REGS - first_reg_offset;
int align_slop = size & 1;
rtx regblock;
regblock = gen_rtx_MEM (BLKmode,
plus_constant (arg_pointer_rtx,
FIRST_PARM_OFFSET (0)
+ align_slop * UNITS_PER_WORD));
set_mem_alias_set (regblock, get_varargs_alias_set ());
set_mem_align (regblock, BITS_PER_WORD);
move_block_from_reg (first_reg_offset, regblock,
MAX_ARC_PARM_REGS - first_reg_offset);
*pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop)
* UNITS_PER_WORD);
}
}
static bool
arc_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
{
switch (code)
{
case CONST_INT:
if (SMALL_INT (INTVAL (x)))
{
*total = 0;
return true;
}
case CONST:
case LABEL_REF:
case SYMBOL_REF:
*total = COSTS_N_INSNS (1);
return true;
case CONST_DOUBLE:
{
rtx high, low;
split_double (x, &high, &low);
*total = COSTS_N_INSNS (!SMALL_INT (INTVAL (high))
+ !SMALL_INT (INTVAL (low)));
return true;
}
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
if (TARGET_SHIFTER)
*total = COSTS_N_INSNS (1);
else if (GET_CODE (XEXP (x, 1)) != CONST_INT)
*total = COSTS_N_INSNS (16);
else
*total = COSTS_N_INSNS (INTVAL (XEXP ((x), 1)));
return false;
default:
return false;
}
}
static int
arc_address_cost (rtx addr)
{
switch (GET_CODE (addr))
{
case REG :
return 1;
case LABEL_REF :
case SYMBOL_REF :
case CONST :
return 2;
case PLUS :
{
register rtx plus0 = XEXP (addr, 0);
register rtx plus1 = XEXP (addr, 1);
if (GET_CODE (plus0) != REG)
break;
switch (GET_CODE (plus1))
{
case CONST_INT :
return SMALL_INT (plus1) ? 1 : 2;
case CONST :
case SYMBOL_REF :
case LABEL_REF :
return 2;
default:
break;
}
break;
}
default:
break;
}
return 4;
}
struct arc_frame_info
{
unsigned int total_size;
unsigned int extra_size;
unsigned int pretend_size;
unsigned int args_size;
unsigned int reg_size;
unsigned int var_size;
unsigned int reg_offset;
unsigned int gmask;
int initialized;
};
static struct arc_frame_info current_frame_info;
static struct arc_frame_info zero_frame_info;
enum arc_function_type
arc_compute_function_type (tree decl)
{
tree a;
static enum arc_function_type fn_type = ARC_FUNCTION_UNKNOWN;
static tree last_fn = NULL_TREE;
if (decl == NULL_TREE)
{
fn_type = ARC_FUNCTION_UNKNOWN;
last_fn = NULL_TREE;
return fn_type;
}
if (decl == last_fn && fn_type != ARC_FUNCTION_UNKNOWN)
return fn_type;
fn_type = ARC_FUNCTION_NORMAL;
for (a = DECL_ATTRIBUTES (current_function_decl);
a;
a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a), args = TREE_VALUE (a);
if (name == get_identifier ("__interrupt__")
&& list_length (args) == 1
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
tree value = TREE_VALUE (args);
if (!strcmp (TREE_STRING_POINTER (value), "ilink1"))
fn_type = ARC_FUNCTION_ILINK1;
else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
fn_type = ARC_FUNCTION_ILINK2;
else
gcc_unreachable ();
break;
}
}
last_fn = decl;
return fn_type;
}
#define ILINK1_REGNUM 29
#define ILINK2_REGNUM 30
#define RETURN_ADDR_REGNUM 31
#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
#define MUST_SAVE_REGISTER(regno, interrupt_p) \
((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
&& (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p)))
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
unsigned int
arc_compute_frame_size (int size )
{
int regno;
unsigned int total_size, var_size, args_size, pretend_size, extra_size;
unsigned int reg_size, reg_offset;
unsigned int gmask;
enum arc_function_type fn_type;
int interrupt_p;
var_size = size;
args_size = current_function_outgoing_args_size;
pretend_size = current_function_pretend_args_size;
extra_size = FIRST_PARM_OFFSET (0);
total_size = extra_size + pretend_size + args_size + var_size;
reg_offset = FIRST_PARM_OFFSET(0) + current_function_outgoing_args_size;
reg_size = 0;
gmask = 0;
fn_type = arc_compute_function_type (current_function_decl);
interrupt_p = ARC_INTERRUPT_P (fn_type);
for (regno = 0; regno <= 31; regno++)
{
if (MUST_SAVE_REGISTER (regno, interrupt_p))
{
reg_size += UNITS_PER_WORD;
gmask |= 1 << regno;
}
}
total_size += reg_size;
if (total_size == extra_size
&& !MUST_SAVE_RETURN_ADDR)
total_size = extra_size = 0;
total_size = ARC_STACK_ALIGN (total_size);
current_frame_info.total_size = total_size;
current_frame_info.extra_size = extra_size;
current_frame_info.pretend_size = pretend_size;
current_frame_info.var_size = var_size;
current_frame_info.args_size = args_size;
current_frame_info.reg_size = reg_size;
current_frame_info.reg_offset = reg_offset;
current_frame_info.gmask = gmask;
current_frame_info.initialized = reload_completed;
return total_size;
}
void
arc_save_restore (FILE *file,
const char *base_reg,
unsigned int offset,
unsigned int gmask,
const char *op)
{
int regno;
if (gmask == 0)
return;
for (regno = 0; regno <= 31; regno++)
{
if ((gmask & (1L << regno)) != 0)
{
fprintf (file, "\t%s %s,[%s,%d]\n",
op, reg_names[regno], base_reg, offset);
offset += UNITS_PER_WORD;
}
}
}
static bool
arc_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
if (size == UNITS_PER_WORD && aligned_p
&& ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
|| GET_CODE (x) == LABEL_REF))
{
fputs ("\t.word\t%st(", asm_out_file);
output_addr_const (asm_out_file, x);
fputs (")\n", asm_out_file);
return true;
}
return default_assemble_integer (x, size, aligned_p);
}
static void
arc_output_function_prologue (FILE *file, HOST_WIDE_INT size)
{
const char *sp_str = reg_names[STACK_POINTER_REGNUM];
const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
unsigned int gmask = current_frame_info.gmask;
enum arc_function_type fn_type = arc_compute_function_type (current_function_decl);
if (ARC_INTERRUPT_P (fn_type))
{
fprintf (file, "\t%s interrupt handler\n",
ASM_COMMENT_START);
fprintf (file, "\tsub %s,%s,16\n", sp_str, sp_str);
}
fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n",
ASM_COMMENT_START, ASM_COMMENT_START,
current_frame_info.var_size,
current_frame_info.reg_size / 4,
current_frame_info.args_size,
current_frame_info.extra_size);
size = ARC_STACK_ALIGN (size);
size = (! current_frame_info.initialized
? arc_compute_frame_size (size)
: current_frame_info.total_size);
gcc_assert (size || !gmask);
if (current_frame_info.pretend_size != 0)
fprintf (file, "\tsub %s,%s,%d\n",
sp_str, sp_str, current_frame_info.pretend_size);
if (MUST_SAVE_RETURN_ADDR)
fprintf (file, "\tst %s,[%s,%d]\n",
reg_names[RETURN_ADDR_REGNUM], sp_str, UNITS_PER_WORD);
if (frame_pointer_needed)
{
fprintf (file, "\tst %s,[%s]\n", fp_str, sp_str);
fprintf (file, "\tmov %s,%s\n", fp_str, sp_str);
}
if (size - current_frame_info.pretend_size > 0)
fprintf (file, "\tsub %s,%s," HOST_WIDE_INT_PRINT_DEC "\n",
sp_str, sp_str, size - current_frame_info.pretend_size);
arc_save_restore (file, sp_str, current_frame_info.reg_offset,
gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
"st");
fprintf (file, "\t%s END PROLOGUE\n", ASM_COMMENT_START);
}
static void
arc_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
{
rtx epilogue_delay = current_function_epilogue_delay_list;
int noepilogue = FALSE;
enum arc_function_type fn_type = arc_compute_function_type (current_function_decl);
fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START);
size = ARC_STACK_ALIGN (size);
size = (!current_frame_info.initialized
? arc_compute_frame_size (size)
: current_frame_info.total_size);
if (size == 0 && epilogue_delay == 0)
{
rtx insn = get_last_insn ();
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
noepilogue = TRUE;
}
if (!noepilogue)
{
unsigned int pretend_size = current_frame_info.pretend_size;
unsigned int frame_size = size - pretend_size;
int restored, fp_restored_p;
int can_trust_sp_p = !current_function_calls_alloca;
const char *sp_str = reg_names[STACK_POINTER_REGNUM];
const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
if (!can_trust_sp_p)
{
gcc_assert (frame_pointer_needed);
fprintf (file,"\tsub %s,%s,%d\t\t%s sp not trusted here\n",
sp_str, fp_str, frame_size, ASM_COMMENT_START);
}
arc_save_restore (file, sp_str, current_frame_info.reg_offset,
current_frame_info.gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
"ld");
if (MUST_SAVE_RETURN_ADDR)
fprintf (file, "\tld %s,[%s,%d]\n",
reg_names[RETURN_ADDR_REGNUM],
frame_pointer_needed ? fp_str : sp_str,
UNITS_PER_WORD + (frame_pointer_needed ? 0 : frame_size));
restored = 0;
fp_restored_p = 0;
if (MUST_SAVE_RETURN_ADDR && epilogue_delay != NULL_RTX)
{
final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
epilogue_delay = NULL_RTX;
}
if (frame_pointer_needed)
{
if (epilogue_delay != NULL_RTX
|| !SMALL_INT (frame_size)
|| pretend_size
|| ARC_INTERRUPT_P (fn_type))
{
fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size);
restored += frame_size;
fp_restored_p = 1;
}
}
else if (!SMALL_INT (size )
|| ARC_INTERRUPT_P (fn_type))
{
fprintf (file, "\tadd %s,%s,%d\n", sp_str, sp_str, frame_size);
restored += frame_size;
}
if (ARC_INTERRUPT_P (fn_type))
{
if (epilogue_delay)
{
final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
}
}
{
static const int regs[4] = {
0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM
};
if (ARC_INTERRUPT_P (fn_type))
fprintf (file, "\tj.d.f %s\n", reg_names[regs[fn_type]]);
else
fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]);
}
if (ARC_INTERRUPT_P (fn_type))
fprintf (file, "\tadd %s,%s,16\n", sp_str, sp_str);
else if (epilogue_delay != NULL_RTX)
{
gcc_assert (!frame_pointer_needed || fp_restored_p);
gcc_assert (restored >= size);
final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
}
else if (frame_pointer_needed && !fp_restored_p)
{
gcc_assert (SMALL_INT (frame_size));
fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size);
}
else if (restored < size)
{
gcc_assert (SMALL_INT (size - restored));
fprintf (file, "\tadd %s,%s," HOST_WIDE_INT_PRINT_DEC "\n",
sp_str, sp_str, size - restored);
}
else
fprintf (file, "\tnop\n");
}
current_frame_info = zero_frame_info;
arc_compute_function_type (NULL_TREE);
}
int
arc_delay_slots_for_epilogue (void)
{
if (arc_compute_function_type (current_function_decl) != ARC_FUNCTION_NORMAL)
return 0;
if (!current_frame_info.initialized)
(void) arc_compute_frame_size (get_frame_size ());
if (current_frame_info.total_size == 0)
return 1;
return 0;
}
int
arc_eligible_for_epilogue_delay (rtx trial, int slot)
{
gcc_assert (!slot);
if (get_attr_length (trial) == 1
&& current_frame_info.gmask == 0
&& ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial))
&& ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial)))
return 1;
return 0;
}
int
shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
return 1;
default:
return 0;
}
}
const char *
output_shift (rtx *operands)
{
rtx shift = operands[3];
enum machine_mode mode = GET_MODE (shift);
enum rtx_code code = GET_CODE (shift);
const char *shift_one;
gcc_assert (mode == SImode);
switch (code)
{
case ASHIFT: shift_one = "asl %0,%0"; break;
case ASHIFTRT: shift_one = "asr %0,%0"; break;
case LSHIFTRT: shift_one = "lsr %0,%0"; break;
default: gcc_unreachable ();
}
if (GET_CODE (operands[2]) != CONST_INT)
{
if (optimize)
{
output_asm_insn ("sub.f 0,%2,0", operands);
output_asm_insn ("mov lp_count,%2", operands);
output_asm_insn ("bz 2f", operands);
}
else
output_asm_insn ("mov %4,%2", operands);
goto shiftloop;
}
else
{
int n = INTVAL (operands[2]);
if (n < 0)
n = 0;
else if (n > GET_MODE_BITSIZE (mode))
n = GET_MODE_BITSIZE (mode);
if (n <= 8)
{
while (--n >= 0)
output_asm_insn (shift_one, operands);
}
else if (n == BITS_PER_WORD - 1)
{
switch (code)
{
case ASHIFT :
output_asm_insn ("and %0,%0,1\n\tror %0,%0", operands);
break;
case ASHIFTRT :
output_asm_insn ("asl.f 0,%0\n\tsbc %0,0,0", operands);
break;
case LSHIFTRT :
output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands);
break;
default:
break;
}
}
else
{
char buf[100];
if (optimize)
output_asm_insn ("mov lp_count,%c2", operands);
else
output_asm_insn ("mov %4,%c2", operands);
shiftloop:
if (optimize)
{
if (flag_pic)
sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start",
ASM_COMMENT_START);
else
sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2",
ASM_COMMENT_START);
output_asm_insn (buf, operands);
output_asm_insn ("sr %4,[lp_start]", operands);
output_asm_insn ("add %4,%4,1", operands);
output_asm_insn ("sr %4,[lp_end]", operands);
output_asm_insn ("nop\n\tnop", operands);
if (flag_pic)
fprintf (asm_out_file, "\t%s single insn loop\n",
ASM_COMMENT_START);
else
fprintf (asm_out_file, "1:\t%s single insn loop\n",
ASM_COMMENT_START);
output_asm_insn (shift_one, operands);
fprintf (asm_out_file, "2:\t%s end single insn loop\n",
ASM_COMMENT_START);
}
else
{
fprintf (asm_out_file, "1:\t%s begin shift loop\n",
ASM_COMMENT_START);
output_asm_insn ("sub.f %4,%4,1", operands);
output_asm_insn ("nop", operands);
output_asm_insn ("bn.nd 2f", operands);
output_asm_insn (shift_one, operands);
output_asm_insn ("b.nd 1b", operands);
fprintf (asm_out_file, "2:\t%s end shift loop\n",
ASM_COMMENT_START);
}
}
}
return "";
}
void
arc_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED,
rtx fnaddr ATTRIBUTE_UNUSED,
rtx cxt ATTRIBUTE_UNUSED)
{
}
static void
arc_file_start (void)
{
default_file_start ();
fprintf (asm_out_file, "\t.cpu %s\n", arc_cpu_string);
}
void
arc_print_operand (FILE *file, rtx x, int code)
{
switch (code)
{
case '#' :
case '*' :
if (!final_sequence || XVECLEN (final_sequence, 0) == 1)
{
fputs (".nd", file);
}
else
{
rtx jump = XVECEXP (final_sequence, 0, 0);
rtx delay = XVECEXP (final_sequence, 0, 1);
if (INSN_ANNULLED_BRANCH_P (jump))
fputs (INSN_FROM_TARGET_P (delay) ? ".jd" : ".nd", file);
else
fputs (".d", file);
}
return;
case '?' :
case '!' :
if (arc_ccfsm_state == 3 || arc_ccfsm_state == 4)
{
if (final_sequence && XVECLEN (final_sequence, 0) == 2)
{
rtx insn = XVECEXP (final_sequence, 0, 1);
if (INSN_ANNULLED_BRANCH_P (insn))
{
if (INSN_FROM_TARGET_P (insn))
fprintf (file, "%s%s",
code == '?' ? "." : "",
arc_condition_codes[ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc)]);
else
fprintf (file, "%s%s",
code == '?' ? "." : "",
arc_condition_codes[arc_ccfsm_current_cc]);
}
else
{
;
}
}
else
{
fprintf (file, "%s%s",
code == '?' ? "." : "",
arc_condition_codes[arc_ccfsm_current_cc]);
}
}
return;
case '~' :
if (last_insn_set_cc_p)
fputs ("nop\n\t", file);
return;
case 'd' :
fputs (arc_condition_codes[get_arc_condition_code (x)], file);
return;
case 'D' :
fputs (arc_condition_codes[ARC_INVERSE_CONDITION_CODE
(get_arc_condition_code (x))],
file);
return;
case 'R' :
if (GET_CODE (x) == REG)
fputs (reg_names[REGNO (x)+1], file);
else if (GET_CODE (x) == MEM)
{
fputc ('[', file);
if (GET_CODE (XEXP (x, 0)) == PRE_INC
|| GET_CODE (XEXP (x, 0)) == PRE_DEC)
output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4));
else
output_address (plus_constant (XEXP (x, 0), 4));
fputc (']', file);
}
else
output_operand_lossage ("invalid operand to %%R code");
return;
case 'S' :
if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
|| GET_CODE (x) == LABEL_REF)
{
fprintf (file, "%%st(");
output_addr_const (file, x);
fprintf (file, ")");
return;
}
break;
case 'H' :
case 'L' :
if (GET_CODE (x) == REG)
{
if ((TARGET_BIG_ENDIAN != 0) ^ (code == 'L'))
fputs (reg_names[REGNO (x)], file);
else
fputs (reg_names[REGNO (x)+1], file);
}
else if (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE)
{
rtx first, second;
split_double (x, &first, &second);
fprintf (file, "0x%08lx",
(long)(code == 'L' ? INTVAL (first) : INTVAL (second)));
}
else
output_operand_lossage ("invalid operand to %%H/%%L code");
return;
case 'A' :
{
char str[30];
gcc_assert (GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1);
fprintf (file, "%s", str);
return;
}
case 'U' :
if (GET_CODE (x) == MEM)
{
if (GET_CODE (XEXP (x, 0)) == PRE_INC
|| GET_CODE (XEXP (x, 0)) == PRE_DEC)
fputs (".a", file);
}
else
output_operand_lossage ("invalid operand to %%U code");
return;
case 'V' :
if (GET_CODE (x) == MEM)
{
if (MEM_VOLATILE_P (x))
fputs (".di", file);
}
else
output_operand_lossage ("invalid operand to %%V code");
return;
case 0 :
break;
default :
output_operand_lossage ("invalid operand output code");
}
switch (GET_CODE (x))
{
case REG :
fputs (reg_names[REGNO (x)], file);
break;
case MEM :
fputc ('[', file);
if (GET_CODE (XEXP (x, 0)) == PRE_INC)
output_address (plus_constant (XEXP (XEXP (x, 0), 0),
GET_MODE_SIZE (GET_MODE (x))));
else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
output_address (plus_constant (XEXP (XEXP (x, 0), 0),
- GET_MODE_SIZE (GET_MODE (x))));
else
output_address (XEXP (x, 0));
fputc (']', file);
break;
case CONST_DOUBLE :
if (GET_MODE (x) == SFmode)
{
REAL_VALUE_TYPE d;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
REAL_VALUE_TO_TARGET_SINGLE (d, l);
fprintf (file, "0x%08lx", l);
break;
}
default :
output_addr_const (file, x);
break;
}
}
void
arc_print_operand_address (FILE *file, rtx addr)
{
register rtx base, index = 0;
int offset = 0;
switch (GET_CODE (addr))
{
case REG :
fputs (reg_names[REGNO (addr)], file);
break;
case SYMBOL_REF :
if ( 0 && SYMBOL_REF_FUNCTION_P (addr))
{
fprintf (file, "%%st(");
output_addr_const (file, addr);
fprintf (file, ")");
}
else
output_addr_const (file, addr);
break;
case PLUS :
if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
else
base = XEXP (addr, 0), index = XEXP (addr, 1);
gcc_assert (GET_CODE (base) == REG);
fputs (reg_names[REGNO (base)], file);
if (index == 0)
{
if (offset != 0)
fprintf (file, ",%d", offset);
}
else
{
switch (GET_CODE (index))
{
case REG:
fprintf (file, ",%s", reg_names[REGNO (index)]);
break;
case SYMBOL_REF:
fputc (',', file), output_addr_const (file, index);
break;
default:
gcc_unreachable ();
}
}
break;
case PRE_INC :
case PRE_DEC :
gcc_unreachable ();
break;
default :
output_addr_const (file, addr);
break;
}
}
static void
record_cc_ref (rtx insn)
{
last_insn_set_cc_p = current_insn_set_cc_p;
switch (get_attr_cond (insn))
{
case COND_SET :
case COND_SET_ZN :
case COND_SET_ZNC :
if (get_attr_length (insn) == 1)
current_insn_set_cc_p = 1;
else
current_insn_set_cc_p = 0;
break;
default :
current_insn_set_cc_p = 0;
break;
}
}
void
arc_final_prescan_insn (rtx insn,
rtx *opvec ATTRIBUTE_UNUSED,
int noperands ATTRIBUTE_UNUSED)
{
register rtx body = PATTERN (insn);
int reverse = 0;
int seeking_return = 0;
rtx start_insn = insn;
record_cc_ref (insn);
if (optimize < 2 || TARGET_NO_COND_EXEC)
return;
if (arc_ccfsm_state == 4)
{
if (insn == arc_ccfsm_target_insn)
{
arc_ccfsm_target_insn = NULL;
arc_ccfsm_state = 0;
}
return;
}
if (arc_ccfsm_state == 3)
{
if (simplejump_p (insn))
{
start_insn = next_nonnote_insn (start_insn);
if (GET_CODE (start_insn) == BARRIER)
{
start_insn = next_nonnote_insn (start_insn);
}
if (GET_CODE (start_insn) == CODE_LABEL
&& CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label
&& LABEL_NUSES (start_insn) == 1)
reverse = TRUE;
else
return;
}
else if (GET_CODE (body) == RETURN)
{
start_insn = next_nonnote_insn (start_insn);
if (GET_CODE (start_insn) == BARRIER)
start_insn = next_nonnote_insn (start_insn);
if (GET_CODE (start_insn) == CODE_LABEL
&& CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label
&& LABEL_NUSES (start_insn) == 1)
{
reverse = TRUE;
seeking_return = 1;
}
else
return;
}
else
return;
}
if (GET_CODE (insn) != JUMP_INSN)
return;
if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
body = XVECEXP (body, 0, 0);
if (reverse
|| (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
&& GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
{
int insns_skipped = 0, fail = FALSE, succeed = FALSE;
int then_not_else = TRUE;
int next_must_be_target_label_p;
rtx this_insn = start_insn, label = 0;
if (reverse)
{
if (!seeking_return)
label = XEXP (SET_SRC (body), 0);
}
else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
label = XEXP (XEXP (SET_SRC (body), 1), 0);
else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
{
label = XEXP (XEXP (SET_SRC (body), 2), 0);
then_not_else = FALSE;
}
else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
seeking_return = 1;
else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
{
seeking_return = 1;
then_not_else = FALSE;
}
else
gcc_unreachable ();
for (insns_skipped = 0, next_must_be_target_label_p = FALSE;
!fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
insns_skipped++)
{
rtx scanbody;
this_insn = next_nonnote_insn (this_insn);
if (!this_insn)
break;
if (next_must_be_target_label_p)
{
if (GET_CODE (this_insn) == BARRIER)
continue;
if (GET_CODE (this_insn) == CODE_LABEL
&& this_insn == label)
{
arc_ccfsm_state = 1;
succeed = TRUE;
}
else
fail = TRUE;
break;
}
scanbody = PATTERN (this_insn);
switch (GET_CODE (this_insn))
{
case CODE_LABEL:
if (this_insn == label)
{
arc_ccfsm_state = 1;
succeed = TRUE;
}
else
fail = TRUE;
break;
case BARRIER:
next_must_be_target_label_p = TRUE;
break;
case CALL_INSN:
if (get_attr_cond (this_insn) == COND_CANUSE)
next_must_be_target_label_p = TRUE;
else
fail = TRUE;
break;
case JUMP_INSN:
if (GET_CODE (scanbody) == SET
&& GET_CODE (SET_DEST (scanbody)) == PC)
{
if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
&& XEXP (SET_SRC (scanbody), 0) == label && !reverse)
{
arc_ccfsm_state = 2;
succeed = TRUE;
}
else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
fail = TRUE;
}
else if (GET_CODE (scanbody) == RETURN
&& seeking_return)
{
arc_ccfsm_state = 2;
succeed = TRUE;
}
else if (GET_CODE (scanbody) == PARALLEL)
{
if (get_attr_cond (this_insn) != COND_CANUSE)
fail = TRUE;
}
break;
case INSN:
if (GET_CODE (scanbody) == SET
|| GET_CODE (scanbody) == PARALLEL)
{
if (get_attr_cond (this_insn) != COND_CANUSE)
fail = TRUE;
}
else
fail = TRUE;
break;
default:
break;
}
}
if (succeed)
{
if ((!seeking_return) && (arc_ccfsm_state == 1 || reverse))
arc_ccfsm_target_label = CODE_LABEL_NUMBER (label);
else
{
gcc_assert (seeking_return || arc_ccfsm_state == 2);
while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
{
this_insn = next_nonnote_insn (this_insn);
gcc_assert (!this_insn
|| (GET_CODE (this_insn) != BARRIER
&& GET_CODE (this_insn) != CODE_LABEL));
}
if (!this_insn)
{
extract_insn_cached (insn);
arc_ccfsm_state = 0;
arc_ccfsm_target_insn = NULL;
return;
}
arc_ccfsm_target_insn = this_insn;
}
if (!reverse)
arc_ccfsm_current_cc = get_arc_condition_code (XEXP (SET_SRC (body),
0));
if (reverse || then_not_else)
arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc);
}
extract_insn_cached (insn);
}
}
void
arc_ccfsm_at_label (const char *prefix, int num)
{
if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num
&& !strcmp (prefix, "L"))
{
arc_ccfsm_state = 0;
arc_ccfsm_target_insn = NULL_RTX;
}
}
int
arc_ccfsm_branch_deleted_p (void)
{
if (arc_ccfsm_state == 1 || arc_ccfsm_state == 2)
return 1;
return 0;
}
void
arc_ccfsm_record_branch_deleted (void)
{
arc_ccfsm_state += 2;
current_insn_set_cc_p = last_insn_set_cc_p;
}
void
arc_va_start (tree valist, rtx nextarg)
{
if (current_function_args_info < 8
&& (current_function_args_info & 1))
nextarg = plus_constant (nextarg, UNITS_PER_WORD);
std_expand_builtin_va_start (valist, nextarg);
}
static void
arc_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
{
arc_ccfsm_at_label (prefix, labelno);
default_internal_label (stream, prefix, labelno);
}
static void
arc_external_libcall (rtx fun ATTRIBUTE_UNUSED)
{
#if 0
if (TARGET_MANGLE_CPU_LIBGCC)
{
fprintf (FILE, "\t.rename\t_%s, _%s%s\n",
XSTR (SYMREF, 0), XSTR (SYMREF, 0),
arc_mangle_suffix);
}
#endif
}
static bool
arc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
if (AGGREGATE_TYPE_P (type))
return true;
else
{
HOST_WIDE_INT size = int_size_in_bytes (type);
return (size == -1 || size > 8);
}
}
static bool
arc_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
enum machine_mode mode, tree type,
bool named ATTRIBUTE_UNUSED)
{
unsigned HOST_WIDE_INT size;
if (type)
{
if (AGGREGATE_TYPE_P (type))
return true;
size = int_size_in_bytes (type);
}
else
size = GET_MODE_SIZE (mode);
return size > 8;
}