#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "insn-addr.h"
#include "flags.h"
#include "reload.h"
#include "tree.h"
#include "expr.h"
#include "toplev.h"
#include "obstack.h"
#include "function.h"
#include "recog.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
#include "basic-block.h"
#define CHAIN_FRAMES (frame_pointer_needed || FRAME_POINTER_REQUIRED)
static int ip2k_naked_function_p PARAMS ((tree));
#ifdef IP2K_MD_REORG_PASS
static void mdr_resequence_xy_yx PARAMS ((rtx));
static void mdr_pres_replace_and_recurse PARAMS ((rtx, rtx, rtx));
static void mdr_propagate_reg_equivs_sequence PARAMS ((rtx, rtx, rtx));
static void mdr_propagate_reg_equivs PARAMS ((rtx));
static int track_dp_reload PARAMS ((rtx , rtx *, int , int));
static void mdr_try_dp_reload_elim PARAMS ((rtx));
static void mdr_try_move_dp_reload PARAMS ((rtx));
static void mdr_try_move_pushes PARAMS ((rtx));
static void mdr_try_propagate_clr_sequence PARAMS ((rtx, unsigned int));
static void mdr_try_propagate_clr PARAMS ((rtx));
static void mdr_try_propagate_move_sequence PARAMS ((rtx, rtx, rtx));
static void mdr_try_propagate_move PARAMS ((rtx));
static void mdr_try_remove_redundant_insns PARAMS ((rtx));
static int track_w_reload PARAMS ((rtx, rtx *, int , int));
static void mdr_try_wreg_elim PARAMS ((rtx));
#endif
static int ip2k_check_can_adjust_stack_ref PARAMS ((rtx, int));
static void ip2k_adjust_stack_ref PARAMS ((rtx *, int));
static int ip2k_xexp_not_uses_reg_for_mem PARAMS ((rtx, unsigned int));
static tree ip2k_handle_progmem_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree ip2k_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int,
bool *));
const struct attribute_spec ip2k_attribute_table[];
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue
#undef TARGET_ASM_UNIQUE_SECTION
#define TARGET_ASM_UNIQUE_SECTION unique_section
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO encode_section_info
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table
struct gcc_target targetm = TARGET_INITIALIZER;
static int commands_in_prologues;
static int commands_in_epilogues;
static int prologue_size;
static int epilogue_size;
rtx ip2k_compare_operands[3];
int ip2k_test_flag;
static int ip2k_stack_delta;
int ip2k_reorg_in_progress = 0;
int ip2k_reorg_completed = 0;
int ip2k_reorg_split_dimode = 0;
int ip2k_reorg_split_simode = 0;
int ip2k_reorg_split_himode = 0;
int ip2k_reorg_split_qimode = 0;
int ip2k_reorg_merge_qimode = 0;
void
ip2k_init_local_alloc (rao)
int * rao;
{
static const int alloc_order[] = REG_ALLOC_ORDER;
memcpy (rao, alloc_order, sizeof (alloc_order));
}
int
ip2k_return_pops_args (fundecl, funtype, size)
tree fundecl ATTRIBUTE_UNUSED;
tree funtype;
int size;
{
if (TREE_CODE (funtype) == IDENTIFIER_NODE)
return size;
if (TYPE_ARG_TYPES (funtype) == NULL_TREE
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
return size;
return 0;
}
static int
ip2k_naked_function_p (func)
tree func;
{
tree a;
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
void
function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int leaf_func_p;
int main_p;
int reg;
rtx operands[2];
prologue_size = epilogue_size = 0;
if (ip2k_naked_function_p (current_function_decl))
{
fprintf (file, "/* prologue: naked */\n");
return;
}
leaf_func_p = leaf_function_p ();
main_p = ! strcmp ("main", current_function_name);
prologue_size = 0;
fprintf (file, "/* prologue: frame size=%d */\n", size);
if (! leaf_func_p)
{
OUT_AS1 (push, calll);
OUT_AS1 (push, callh);
prologue_size += 4;
}
if (CHAIN_FRAMES)
{
OUT_AS1 (push, REG_FP+1);
OUT_AS2 (mov, w, spl);
OUT_AS2 (mov, REG_FP+1, w);
OUT_AS2 (mov, w, sph);
OUT_AS1 (push, REG_FP);
OUT_AS2 (mov, REG_FP, w);
prologue_size += 12;
}
for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1);
reg > 0; --reg)
{
if (regs_ever_live[reg] && ! call_used_regs[reg])
{
fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]);
prologue_size += 2;
}
}
if (size)
{
operands[0] = GEN_INT (size);
switch (size & 0xff)
{
case 0:
break;
case 1:
OUT_AS1 (dec, spl);
prologue_size += 2;
break;
default:
OUT_AS2 (mov, w, %L0);
OUT_AS2 (sub, spl, w);
prologue_size += 4;
}
switch (size & 0xff00)
{
case 0:
break;
case 0x100:
OUT_AS1 (dec, sph);
prologue_size += 2;
break;
default:
if ((size & 0xff) != ((size >> 8) & 0xff))
OUT_AS2 (mov, w, %H0);
OUT_AS2 (sub, sph, w);
prologue_size += 4;
}
}
if (flag_stack_check)
{
OUT_AS2 (mov, w, sph);
OUT_AS2 (cmp, w, #%%hi8data(_end));
OUT_AS1 (sc, );
OUT_AS1 (page, 1f);
OUT_AS1 (jmp, 1f);
OUT_AS1 (sz, );
OUT_AS1 (page,0f);
OUT_AS1 (jmp,0f);
OUT_AS2 (mov, w, spl);
OUT_AS2 (cmp, w, #%%lo8data(_end));
OUT_AS1 (sc,);
OUT_AS1 (page,1f);
OUT_AS1 (jmp,1f);
OUT_AS1 (0:,);
output_asm_insn ("push\t$ff", operands);
OUT_AS1 (system,);
OUT_AS1 (1:, );
prologue_size += 30;
}
}
void
function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int leaf_func_p;
int reg,savelimit;
rtx operands[2];
int args_locals_size = current_function_args_size;
int saved_regs_p = 0;
int need_ret = 1;
ip2k_reorg_in_progress = 0;
ip2k_reorg_completed = 0;
ip2k_reorg_split_dimode = 0;
ip2k_reorg_split_simode = 0;
ip2k_reorg_split_himode = 0;
ip2k_reorg_split_qimode = 0;
ip2k_reorg_merge_qimode = 0;
if (ip2k_naked_function_p (current_function_decl))
{
fprintf (file, "/* epilogue: naked */\n");
return;
}
leaf_func_p = leaf_function_p ();
epilogue_size = 0;
fprintf (file, "/* epilogue: frame size=%d */\n", size);
savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2);
for (reg = 0; reg < savelimit; reg++)
if (regs_ever_live[reg] && ! call_used_regs[reg])
{
saved_regs_p = 1;
break;
}
if (size)
{
if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p
&& current_function_pops_args)
args_locals_size = current_function_args_size + size;
else
{
operands[0] = GEN_INT (size);
switch (size & 0xff)
{
default:
OUT_AS2 (mov, w, %L0);
OUT_AS2 (add, spl, w);
epilogue_size += 4;
case 0:
break;
case 1:
OUT_AS1 (inc, spl);
epilogue_size += 2;
}
switch (size & 0xff00)
{
default:
if ((size & 0xff) != ((size >> 8) & 0xff))
OUT_AS2 (mov, w, %H0);
OUT_AS2 (add, sph, w);
epilogue_size += 4;
case 0:
break;
case 0x100:
OUT_AS1 (inc, sph);
epilogue_size += 2;
}
}
}
for (reg = 0; reg < savelimit; reg++)
{
if (regs_ever_live[reg] && ! call_used_regs[reg])
{
fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]);
prologue_size += 2;
}
}
if (CHAIN_FRAMES
&& ! (current_function_pops_args
&& current_function_args_size >= 2
&& current_function_args_size < 0x100))
{
OUT_AS1 (pop, REG_FP);
OUT_AS1 (pop, REG_FP+1);
epilogue_size += 4;
}
if (! leaf_func_p)
{
if (current_function_pops_args
&& current_function_args_size >= 2
&& current_function_args_size < 0x100)
{
if (current_function_args_size == 2)
{
if (CHAIN_FRAMES)
{
OUT_AS1 (page, __fp_pop2_args_ret);
OUT_AS1 (jmp, __fp_pop2_args_ret);
}
else
{
OUT_AS1 (page, __pop2_args_ret);
OUT_AS1 (jmp, __pop2_args_ret);
}
epilogue_size += 4;
}
else
{
operands[0] = GEN_INT (current_function_args_size);
OUT_AS2 (mov, w, %L0);
if (CHAIN_FRAMES)
{
OUT_AS1 (page, __fp_pop_args_ret);
OUT_AS1 (jmp, __fp_pop_args_ret);
}
else
{
OUT_AS1 (page, __pop_args_ret);
OUT_AS1 (jmp, __pop_args_ret);
}
epilogue_size += 6;
}
need_ret = 0;
}
else
{
OUT_AS1 (pop, callh);
OUT_AS1 (pop, calll);
epilogue_size += 4;
}
}
else
{
if (current_function_pops_args
&& args_locals_size >= 2
&& args_locals_size < 0x100)
{
if (args_locals_size == 2)
{
if (CHAIN_FRAMES)
{
OUT_AS1 (page, __leaf_fp_pop2_args_ret);
OUT_AS1 (jmp, __leaf_fp_pop2_args_ret);
epilogue_size += 4;
need_ret = 0;
}
}
else
{
operands[0] = GEN_INT (args_locals_size);
if (CHAIN_FRAMES)
{
OUT_AS2 (mov, w, %L0);
OUT_AS1 (page, __leaf_fp_pop_args_ret);
OUT_AS1 (jmp, __leaf_fp_pop_args_ret);
epilogue_size += 6;
need_ret = 0;
}
}
}
}
if (current_function_pops_args && args_locals_size && need_ret)
{
operands[0] = GEN_INT (args_locals_size);
switch (args_locals_size & 0xff)
{
default:
OUT_AS2 (mov, w, %L0);
OUT_AS2 (add, spl, w);
epilogue_size += 4;
case 0:
break;
case 1:
OUT_AS1 (inc, spl);
epilogue_size += 2;
}
switch (args_locals_size & 0xff00)
{
default:
if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff))
OUT_AS2 (mov, w, %H0);
OUT_AS2 (add, sph, w);
epilogue_size += 4;
case 0:
break;
case 0x100:
OUT_AS1 (inc, sph);
epilogue_size += 2;
}
}
if (need_ret)
{
OUT_AS1 (ret,);
epilogue_size += 2;
}
fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
commands_in_prologues += prologue_size;
commands_in_epilogues += epilogue_size;
}
int
ip2k_init_elim_offset (from, to)
int from;
int to;
{
int leaf_func_p = leaf_function_p ();
int no_saved_pc = leaf_func_p
|| ip2k_naked_function_p (current_function_decl);
int offset;
int reg;
int reglimit;
if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return get_frame_size () + 1;
if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
return (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
reglimit = CHAIN_FRAMES ? REG_FP : (REG_FP + 2);
for (offset = 0,reg = 0; reg < reglimit; ++reg)
{
if ((regs_ever_live[reg] && ! call_used_regs[reg]))
{
++offset;
}
}
if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
return -offset;
if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return offset + get_frame_size () + 1;
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return offset + get_frame_size () + 1
+ (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
abort ();
}
int
legitimate_address_p (mode, x, strict)
enum machine_mode mode;
rtx x;
int strict;
{
int off;
if (GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
switch (GET_CODE (x))
{
case REG:
if (REGNO (x) == REG_IP)
return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
if (strict ? REG_OK_FOR_BASE_STRICT_P (x)
: REG_OK_FOR_BASE_NOSTRICT_P (x))
return 'S';
break;
case PLUS:
{
rtx op1, op2;
op1 = XEXP (x, 0);
op2 = XEXP (x, 1);
if (REG_P (op2) && ! REG_P (op1))
{
rtx tmp = op1;
op1 = op2;
op2 = tmp;
}
if (! REG_P (op1)
|| REG_P (op2)
|| GET_CODE (op2) != CONST_INT)
return 0;
switch (REGNO (op1))
{
case REG_DP:
case REG_SP:
off = 2 * GET_MODE_SIZE (mode);
if (! off)
off = 1;
if (INTVAL (op2) < 0 || INTVAL (op2) > (128 - off))
return 0;
return 'S';
case REG_IP:
if (GET_MODE_SIZE (mode) <= 1 && INTVAL (op2) == 0)
return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
return 0;
case REG_AP:
case REG_FP:
case REG_VFP:
default:
if (strict || ! REG_OK_FOR_BASE_NOSTRICT_P (op1))
return 0;
return 'S';
}
}
break;
case CONST:
case SYMBOL_REF:
return is_regfile_address (x) ? 0 : 'C';
case LABEL_REF:
return 'L';
default:
return 0;
}
return 0;
}
int
ip2k_mode_dependent_address (addr)
rtx addr;
{
switch (GET_CODE (addr))
{
case POST_INC:
case POST_DEC:
case PRE_INC:
case PRE_DEC:
return 1;
case REG:
return (REGNO (addr) == REG_IP);
default:
return 0;
}
}
rtx
legitimize_address (x, oldx, mode, scratch)
rtx x;
rtx oldx ATTRIBUTE_UNUSED;
rtx scratch;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx reg;
if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& ! CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'K'))
{
int offset = INTVAL (XEXP (x, 1));
reg = scratch ? scratch : gen_reg_rtx (Pmode);
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_PLUS (Pmode, XEXP (x, 0),
GEN_INT (offset & 0xffc0))));
x = gen_rtx_PLUS (Pmode, reg, GEN_INT (offset & 0x3f));
}
return x;
}
int
is_regfile_address (x)
rtx x;
{
while (1)
switch (GET_CODE (x))
{
case SYMBOL_REF:
return ! SYMBOL_REF_FLAG (x);
case CONST:
case PLUS:
x = XEXP (x, 0);
break;
case CONST_INT:
case REG:
case SUBREG:
return 1;
case LABEL_REF:
return 0;
default:
return 0;
}
return 0;
}
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
switch (GET_CODE (addr))
{
case SUBREG:
addr = alter_subreg (&addr);
case REG:
fprintf (file, "(%s)",
REGNO (addr) == REG_DP ? "DP"
: REGNO (addr) == REG_SP ? "SP"
: REGNO (addr) == REG_IP ? "IP"
: REGNO (addr) == REG_VFP ? "VFP"
: REGNO (addr) == REG_AP ? "AP"
: reg_names[REGNO (addr)]);
break;
case PRE_DEC:
case POST_INC:
abort ();
break;
case CONST:
addr = XEXP (addr, 0);
print_operand_address (file, XEXP (addr, 0));
fprintf (file, "+");
print_operand_address (file, XEXP (addr, 1));
return;
case LO_SUM:
if (is_regfile_address (XEXP (addr, 1)))
fprintf (file, "%%lo8data(");
else
fprintf (file, "%%lo8insn(");
print_operand_address (file, XEXP (addr, 1));
fprintf (file, ")");
print_operand_address (file, XEXP (addr, 0));
break;
case PLUS:
if (XEXP (addr, 1) == const0_rtx
&& GET_CODE (XEXP (addr, 0)) == PLUS)
{
print_operand_address (file, XEXP (addr, 0));
return;
}
if (! REG_P (XEXP (addr, 0)) || REGNO (XEXP (addr, 0)) != REG_IP)
print_operand_address (file, XEXP (addr, 1));
print_operand_address (file, XEXP (addr, 0));
break;
case HIGH:
if (is_regfile_address (XEXP (addr, 0)))
fprintf (file, "%%hi8data(");
else
fprintf (file, "%%hi8insn(");
output_addr_const (file, XEXP (addr, 0));
fprintf (file, ")");
break;
default:
output_addr_const (file, addr);
}
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
int abcd = 0;
unsigned long value;
switch (code)
{
case '<':
ip2k_stack_delta++;
return;
case '>':
ip2k_stack_delta--;
return;
case 'A':
case 'B':
case 'C':
case 'D':
abcd = code - 'A';
break;
case 'H':
abcd = 0;
break;
case 'L':
abcd = 1;
break;
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
abcd = code - 'S';
default:
break;
}
if (ip2k_short_operand (x, GET_MODE (x))
&& ip2k_address_uses_reg_p (x, REG_SP))
abcd += ip2k_stack_delta;
switch (GET_CODE (x))
{
case SUBREG:
x = alter_subreg (&x);
case REG:
fprintf (file, reg_names[true_regnum (x) + abcd]);
break;
case CONST_INT:
switch (code)
{
case 'x':
fprintf (file, "$%x", INTVAL (x) & 0xffff);
break;
case 'b':
fprintf (file, "%d", INTVAL (x));
break;
case 'e':
fprintf (file, "#%d", 1 << INTVAL (x));
break;
case 'A':
case 'B':
case 'C':
case 'D':
value = INTVAL (x);
value >>= 8 * (3 - abcd);
value &= 0xff;
fprintf (file, "#%ld", value);
break;
case 'H':
fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff);
break;
case 'L':
fprintf (file, "#%d", INTVAL (x) & 0xff);
break;
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
value = ((unsigned long long)INTVAL (x)) >> (8 * (7 - abcd)) & 0xff;
fprintf (file, "#%ld", value);
break;
default:
fprintf (file, "#%d", INTVAL (x));
}
break;
case SYMBOL_REF:
case LABEL_REF:
case CODE_LABEL:
case CONST:
switch (code)
{
case 'A':
case 'B':
case 'C':
case 'D':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
abort ();
break;
case 'H':
fprintf (file, "#%s(",
is_regfile_address (x) ? "%hi8data"
: "%hi8insn");
print_operand_address (file, x);
fputc (')', file);
break;
case 'L':
fprintf (file, "#%s(",
is_regfile_address (x) ? "%lo8data"
: "%lo8insn");
print_operand_address (file, x);
fputc (')', file);
break;
default:
print_operand_address (file, x);
}
break;
case MEM:
{
rtx addr = XEXP (x, 0);
if (GET_CODE (addr) == SUBREG)
addr = alter_subreg (&x);
if (CONSTANT_P (addr) && abcd)
{
fputc ('(', file);
print_operand_address (file, addr);
fprintf (file, ")+%d", abcd);
}
else if (abcd)
{
switch (GET_CODE (addr))
{
case PLUS:
abcd += INTVAL (XEXP (addr, 1));
if (GET_CODE (XEXP (addr, 0)) == PLUS)
{
addr = XEXP (addr, 0);
abcd += INTVAL (XEXP (addr, 1));
}
fprintf (file, "%d", abcd);
print_operand_address (file, XEXP (addr, 0));
break;
case REG:
default:
fprintf (file, "%d", abcd);
print_operand_address (file, addr);
}
}
else if (GET_CODE (addr) == REG
&& (REGNO (addr) == REG_DP || REGNO (addr) == REG_SP))
{
fprintf (file, "0");
print_operand_address (file, addr);
}
else
print_operand_address (file, addr);
}
break;
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
{
switch (code)
{
case 'S':
case 'T':
case 'U':
case 'V':
value = CONST_DOUBLE_HIGH (x);
value >>= 8 * (3 - abcd);
value &= 0xff;
fprintf (file, "#%ld", value);
break;
case 'W':
case 'X':
case 'Y':
case 'Z':
value = CONST_DOUBLE_LOW (x);
value >>= 8 * (7 - abcd);
value &= 0xff;
fprintf (file, "#%ld", value);
break;
}
}
else
{
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, value);
fprintf (file, "0x%lx", value);
}
break;
default:
fatal_insn ("bad operand", x);
}
}
const char *
ip2k_set_compare (x, y)
rtx x;
rtx y;
{
ip2k_compare_operands[0] = x;
ip2k_compare_operands[1] = y;
return "";
}
const char *
ip2k_gen_sCOND (insn, code, dest)
rtx insn ATTRIBUTE_UNUSED;
enum rtx_code code;
rtx dest;
{
#define operands ip2k_compare_operands
enum machine_mode mode;
operands[2] = dest;
mode = GET_MODE (operands[0]);
if ((mode != QImode) && (mode != HImode)
&& (mode != SImode) && (mode != DImode))
mode = GET_MODE (operands[1]);
if (mode == QImode
&& !rtx_equal_p (operands[0], operands[2])
&& !rtx_equal_p (operands[1], operands[2])
&& (! REG_P (operands[2])
|| (ip2k_xexp_not_uses_reg_p (operands[0], REGNO (operands[2]), 1)
&& ip2k_xexp_not_uses_reg_p (operands[1],
REGNO (operands[2]), 1))))
{
OUT_AS1 (clr, %2);
if (immediate_operand (operands[1], QImode)
&& ((INTVAL (operands[1]) & 0xff) == 0xff))
{
if (code == EQ)
OUT_AS2 (incsnz, w, %0);
else
OUT_AS2 (incsz, w, %0);
}
else if (immediate_operand (operands[1], QImode)
&& ((INTVAL (operands[1]) & 0xff) == 0x01))
{
if (code == EQ)
OUT_AS2 (decsnz, w, %0);
else
OUT_AS2 (decsz, w, %0);
}
else if (ip2k_compare_operands[1] == const0_rtx)
{
OUT_AS2 (mov, w, %0);
if (code == EQ)
OUT_AS1 (snz,);
else
OUT_AS1 (sz,);
}
else
{
OUT_AS2 (mov, w, %0);
if (code == EQ)
OUT_AS2 (csne, w, %1);
else
OUT_AS2 (cse, w, %1);
}
OUT_AS1 (inc, %2);
}
else
{
if (ip2k_compare_operands[1] == const0_rtx)
{
switch (mode)
{
case QImode:
OUT_AS2 (mov, w, %0);
break;
case HImode:
OUT_AS2 (mov, w, %H0);
OUT_AS2 (or, w, %L0);
break;
case SImode:
OUT_AS2 (mov, w, %A0);
OUT_AS2 (or, w, %B0);
OUT_AS2 (or, w, %C0);
OUT_AS2 (or, w, %D0);
break;
case DImode:
OUT_AS2 (mov, w, %S0);
OUT_AS2 (or, w, %T0);
OUT_AS2 (or, w, %U0);
OUT_AS2 (or, w, %V0);
OUT_AS2 (or, w, %W0);
OUT_AS2 (or, w, %X0);
OUT_AS2 (or, w, %Y0);
OUT_AS2 (or, w, %Z0);
break;
default:
abort ();
}
}
else
{
switch (mode)
{
case QImode:
OUT_AS2 (mov, w, %1);
OUT_AS2 (cmp, w, %0);
break;
case HImode:
OUT_AS2 (mov, w, %H1);
OUT_AS2 (cmp, w, %H0);
OUT_AS1 (sz,);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %L1);
OUT_AS2 (cmp, w, %L0);
OUT_AS1 (2:,);
break;
case SImode:
if (code == EQ)
{
OUT_AS2 (mov, w, #1);
OUT_AS2 (mov, mulh, w);
}
else
OUT_AS1 (clr, mulh);
OUT_AS2 (mov, w, %A1);
OUT_AS2 (cse, w, %A0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %B1);
OUT_AS2 (cse, w, %B0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %C1);
OUT_AS2 (cse, w, %C0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %D1);
OUT_AS2 (cse, w, %D0);
OUT_AS1 (2:,);
if (code == EQ)
OUT_AS1 (dec, mulh);
else
OUT_AS1 (inc, mulh);
OUT_AS2 (mov, w, mulh);
OUT_AS2 (mov, %2, w);
return "";
case DImode:
if (code == EQ)
{
OUT_AS2 (mov, w, #1);
OUT_AS2 (mov, mulh, w);
}
else
OUT_AS1 (clr, mulh);
OUT_AS2 (mov, w, %S1);
OUT_AS2 (cse, w, %S0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %T1);
OUT_AS2 (cse, w, %T0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %U1);
OUT_AS2 (cse, w, %U0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %V1);
OUT_AS2 (cse, w, %V0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %W1);
OUT_AS2 (cse, w, %W0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %X1);
OUT_AS2 (cse, w, %X0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %Y1);
OUT_AS2 (cse, w, %Y0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %Z1);
OUT_AS2 (cse, w, %Z0);
OUT_AS1 (2:,);
if (code == EQ)
OUT_AS1 (dec, mulh);
else
OUT_AS1 (inc, mulh);
OUT_AS2 (mov, w, mulh);
OUT_AS2 (mov, %2, w);
return "";
default:
abort ();
}
}
OUT_AS2 (mov, w, #0);
if (code == EQ)
OUT_AS1 (snz,);
else
OUT_AS1 (sz,);
OUT_AS1 (inc, wreg);
OUT_AS2 (mov, %2, w);
}
return "";
#undef operands
}
const char *
ip2k_gen_signed_comp_branch (insn, code, label)
rtx insn;
enum rtx_code code;
rtx label;
{
#define operands ip2k_compare_operands
enum machine_mode mode;
int can_use_skip = 0;
rtx ninsn;
operands[2] = label;
mode = GET_MODE (operands[0]);
if ((mode != QImode) && (mode != HImode)
&& (mode != SImode) && (mode != DImode))
mode = GET_MODE (operands[1]);
ninsn = next_real_insn (insn);
if (ninsn
&& (recog_memoized (ninsn) >= 0)
&& get_attr_skip (ninsn) == SKIP_YES)
{
rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
if (label == skip_tgt)
can_use_skip = 1;
else
{
if (GET_CODE (skip_tgt) == CODE_LABEL)
skip_tgt = next_nonnote_insn (skip_tgt);
if (GET_CODE (skip_tgt) == JUMP_INSN)
{
rtx set = single_set (skip_tgt);
if (GET_CODE (XEXP (set, 0)) == PC
&& GET_CODE (XEXP (set, 1)) == LABEL_REF
&& label == JUMP_LABEL (skip_tgt))
can_use_skip = 2;
}
}
}
extract_constrain_insn_cached (insn);
if (ip2k_compare_operands[1] == const0_rtx)
{
switch (code)
{
case LT:
if (can_use_skip)
{
OUT_AS2 (sb, %0, 7);
}
else
{
OUT_AS2 (snb, %0, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GT:
switch (mode)
{
case DImode:
OUT_AS2 (rl, w, %S0);
OUT_AS2 (mov, w, %S0);
OUT_AS2 (or, w, %T0);
OUT_AS2 (or, w, %U0);
OUT_AS2 (or, w, %V0);
OUT_AS2 (or, w, %W0);
OUT_AS2 (or, w, %X0);
OUT_AS2 (or, w, %Y0);
OUT_AS2 (or, w, %Z0);
OUT_AS1 (snz, );
OUT_AS2 (setb, status, 0);
OUT_AS2 (sb, status, 0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case SImode:
OUT_AS2 (rl, w, %A0);
OUT_AS2 (mov, w, %A0);
OUT_AS2 (or, w, %B0);
OUT_AS2 (or, w, %C0);
OUT_AS2 (or, w, %D0);
OUT_AS1 (snz, );
OUT_AS2 (setb, status, 0);
OUT_AS2 (sb, status, 0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case HImode:
OUT_AS2 (rl, w, %H0);
OUT_AS2 (mov, w, %H0);
OUT_AS2 (or, w, %L0);
OUT_AS1 (snz, );
OUT_AS2 (setb, status, 0);
OUT_AS2 (sb, status, 0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case QImode:
OUT_AS2 (mov, w, %0);
OUT_AS1 (snz, );
OUT_AS2 (setb, wreg, 7);
OUT_AS2 (sb, wreg, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
default:
abort ();
}
break;
case LE:
switch (mode)
{
case DImode:
OUT_AS2 (mov, w, %S0);
OUT_AS2 (or, w, %T0);
OUT_AS2 (or, w, %U0);
OUT_AS2 (or, w, %V0);
OUT_AS2 (or, w, %W0);
OUT_AS2 (or, w, %X0);
OUT_AS2 (or, w, %Y0);
OUT_AS2 (or, w, %Z0);
OUT_AS1 (sz, );
OUT_AS2 (snb, %S0, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case SImode:
OUT_AS2 (mov, w, %A0);
OUT_AS2 (or, w, %B0);
OUT_AS2 (or, w, %C0);
OUT_AS2 (or, w, %D0);
OUT_AS1 (sz, );
OUT_AS2 (snb, %A0, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case HImode:
OUT_AS2 (mov, w, %H0);
OUT_AS2 (or, w, %L0);
OUT_AS1 (sz, );
OUT_AS2 (snb, %H0, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case QImode:
OUT_AS2 (mov, w, %0);
OUT_AS1 (sz, );
OUT_AS2 (snb, wreg, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
default:
abort ();
}
break;
case GE:
if (can_use_skip)
{
OUT_AS2 (snb, %0, 7);
}
else
{
OUT_AS2 (sb, %0, 7);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
default:
abort ();
}
return "";
}
switch (mode)
{
case QImode:
OUT_AS1 (push, %1%<);
OUT_AS1 (push, %0%>);
OUT_AS1 (page, __cmpqi2);
OUT_AS1 (call, __cmpqi2);
break;
case HImode:
OUT_AS1 (push, %L1%<);
OUT_AS1 (push, %H1%<);
OUT_AS1 (push, %L0%<);
OUT_AS1 (push, %H0%>%>%>);
OUT_AS1 (page, __cmphi2);
OUT_AS1 (call, __cmphi2);
break;
case SImode:
OUT_AS1 (push, %D1%<);
OUT_AS1 (push, %C1%<);
OUT_AS1 (push, %B1%<);
OUT_AS1 (push, %A1%<);
OUT_AS1 (push, %D0%<);
OUT_AS1 (push, %C0%<);
OUT_AS1 (push, %B0%<);
OUT_AS1 (push, %A0%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpsi2);
OUT_AS1 (call, __cmpsi2);
break;
case DImode:
if (GET_CODE (operands[0]) == MEM
&& true_regnum (XEXP (operands[0], 0)) == REG_DP)
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2_dp);
OUT_AS1 (call, __cmpdi2_dp);
}
else
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%<);
OUT_AS1 (push, %Z0%<);
OUT_AS1 (push, %Y0%<);
OUT_AS1 (push, %X0%<);
OUT_AS1 (push, %W0%<);
OUT_AS1 (push, %V0%<);
OUT_AS1 (push, %U0%<);
OUT_AS1 (push, %T0%<);
OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2);
OUT_AS1 (call, __cmpdi2);
}
break;
default:
abort ();
}
switch (code)
{
case LT:
if (can_use_skip)
{
OUT_AS2 (cse, w, #0);
}
else
{
OUT_AS2 (csne, w, #0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GT:
if (can_use_skip)
{
OUT_AS2 (cse, w, #2);
}
else
{
OUT_AS2 (csne, w, #2);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LE:
if (can_use_skip)
{
OUT_AS2 (snb, wreg, 1);
}
else
{
OUT_AS2 (sb, wreg, 1);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GE:
if (can_use_skip)
{
OUT_AS2 (csne, w, #0);
}
else
{
OUT_AS2 (cse, w, #0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
default:
abort ();
}
return "";
#undef operands
}
const char *
ip2k_gen_unsigned_comp_branch (insn, code, label)
rtx insn;
enum rtx_code code;
rtx label;
{
#define operands ip2k_compare_operands
enum machine_mode mode;
int imm_sub = 0;
int imm_cmp = 0;
int can_use_skip = 0;
rtx ninsn;
HOST_WIDE_INT const_low;
HOST_WIDE_INT const_high;
operands[2] = label;
mode = GET_MODE (operands[0]);
if ((mode != QImode) && (mode != HImode) && (mode != SImode)
&& (mode != DImode))
{
mode = GET_MODE (operands[1]);
}
ninsn = next_real_insn (insn);
if (ninsn
&& (recog_memoized (ninsn) >= 0)
&& get_attr_skip (ninsn) == SKIP_YES)
{
rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
if (label == skip_tgt)
can_use_skip = 1;
else
{
if (GET_CODE (skip_tgt) == CODE_LABEL)
skip_tgt = next_nonnote_insn (skip_tgt);
if (GET_CODE (skip_tgt) == JUMP_INSN)
{
rtx set = single_set (skip_tgt);
if (GET_CODE (XEXP (set, 0)) == PC
&& GET_CODE (XEXP (set, 1)) == LABEL_REF
&& label == JUMP_LABEL (skip_tgt))
can_use_skip = 2;
}
}
}
extract_constrain_insn_cached (insn);
if (ip2k_compare_operands[1] == const0_rtx)
{
switch (code)
{
case LEU:
code = EQ;
goto zero;
case GTU:
code = NE;
case EQ:
case NE:
zero:
switch (mode)
{
case DImode:
OUT_AS2 (mov, w, %S0);
OUT_AS2 (or, w, %T0);
OUT_AS2 (or, w, %U0);
OUT_AS2 (or, w, %V0);
OUT_AS2 (or, w, %W0);
OUT_AS2 (or, w, %X0);
OUT_AS2 (or, w, %Y0);
OUT_AS2 (or, w, %Z0);
break;
case SImode:
OUT_AS2 (mov, w, %A0);
OUT_AS2 (or, w, %B0);
OUT_AS2 (or, w, %C0);
OUT_AS2 (or, w, %D0);
break;
case HImode:
OUT_AS2 (mov, w, %H0);
OUT_AS2 (or, w, %L0);
break;
case QImode:
OUT_AS2 (mov, w, %0);
break;
default:
abort ();
}
if (can_use_skip)
{
if (code == EQ)
OUT_AS1 (sz, );
else
OUT_AS1 (snz, );
}
else
{
if (code == EQ)
OUT_AS1 (snz,);
else
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GEU:
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case LTU:
break;
default:
abort ();
}
return "";
}
if (mode != QImode)
{
if ((immediate_operand (operands[1], GET_MODE (operands[1]))
&& ((code == LEU) || (code == GTU)))
|| (immediate_operand (operands[0], GET_MODE (operands[0]))
&& ((code == LTU) || (code == GEU))))
{
imm_sub = 1;
}
}
if ((code == EQ) || (code == NE))
{
imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1]));
if (! imm_cmp)
{
imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0]));
if (imm_cmp)
{
rtx tmp = operands[1];
operands[1] = operands[0];
operands[0] = tmp;
}
}
}
switch (mode)
{
case QImode:
switch (code)
{
case EQ:
if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
OUT_AS2 (incsnz, w, %0);
else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
OUT_AS2 (decsnz, w, %0);
else
{
OUT_AS2 (mov, w, %1);
OUT_AS2 (csne, w, %0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case NE:
if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
OUT_AS2 (incsz, w, %0);
else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
OUT_AS2 (decsz, w, %0);
else
{
OUT_AS2 (mov, w, %1);
OUT_AS2 (cse, w, %0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case GTU:
OUT_AS2 (mov, w, %0);
OUT_AS2 (cmp, w, %1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case GEU:
OUT_AS2 (mov, w, %1);
OUT_AS2 (cmp, w, %0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case LTU:
OUT_AS2 (mov, w, %1);
OUT_AS2 (cmp, w, %0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
case LEU:
OUT_AS2 (mov, w, %0);
OUT_AS2 (cmp, w, %1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
default:
abort ();
}
break;
case HImode:
switch (code)
{
case EQ:
{
unsigned char h = 0, l = 1;
if (imm_cmp)
{
h = (INTVAL (operands[1]) >> 8) & 0xff;
l = INTVAL (operands[1]) & 0xff;
if ((h == 0xff) && (l == 0xff))
{
OUT_AS2 (incsnz, w, %L0);
OUT_AS2 (incsz, w, %H0);
OUT_AS1 (page, 1f);
OUT_AS1 (jmp, 1f);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS1 (1:,);
break;
}
else if (h == 0)
{
if (l == 1)
OUT_AS2 (dec, w, %L0);
else
{
OUT_AS2 (mov, w, %L0);
OUT_AS2 (sub, w, %L1);
}
OUT_AS2 (or, w, %H0);
OUT_AS1 (snz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
}
else if (l == 0)
{
if (h == 1)
OUT_AS2 (dec, w, %H0);
else
{
OUT_AS2 (mov, w, %H0);
OUT_AS2 (sub, w, %H1);
}
OUT_AS2 (or, w, %L0);
OUT_AS1 (snz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
}
}
OUT_AS2 (mov, w, %H1);
OUT_AS2 (cse, w, %H0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
if (! imm_cmp || (h != l))
OUT_AS2 (mov, w, %L1);
OUT_AS2 (csne, w, %L0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS1 (2:,);
}
break;
case NE:
{
unsigned char h = 0, l = 1;
if (imm_cmp)
{
h = (INTVAL (operands[1]) >> 8) & 0xff;
l = INTVAL (operands[1]) & 0xff;
if ((h == 0xff) && (l == 0xff))
{
OUT_AS2 (incsnz, w, %L0);
OUT_AS2 (incsz, w, %H0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
}
else if (h == 0)
{
if (l == 1)
OUT_AS2 (dec, w, %L0);
else
{
OUT_AS2 (mov, w, %L0);
OUT_AS2 (sub, w, %L1);
}
OUT_AS2 (or, w, %H0);
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
}
else if (l == 0)
{
if (h == 1)
OUT_AS2 (dec, w, %H0);
else
{
OUT_AS2 (mov, w, %H0);
OUT_AS2 (sub, w, %H1);
}
OUT_AS2 (or, w, %L0);
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
break;
}
}
OUT_AS2 (mov, w, %H1);
if (imm_cmp && (h == l))
{
OUT_AS2 (csne, w, %H0);
OUT_AS2 (cse, w, %L0);
}
else
{
OUT_AS2 (cse, w, %H0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %L1);
OUT_AS2 (cse, w, %L0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GTU:
if (imm_sub)
{
if ((INTVAL (operands[1]) & 0xffff) != 0xffff)
{
operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
OUT_AS2 (mov, w, %L3);
OUT_AS2 (sub, w, %L0);
OUT_AS2 (mov, w, %H3);
OUT_AS2 (subc, w, %H0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %L0);
OUT_AS2 (sub, w, %L1);
OUT_AS2 (mov, w, %H0);
OUT_AS2 (subc, w, %H1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GEU:
if (imm_sub)
{
if (INTVAL (operands[0]) == 0)
{
OUT_AS2 (mov, w, %H1);
OUT_AS2 (or, w, %L1);
OUT_AS1 (snz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
OUT_AS2 (mov, w, %L3);
OUT_AS2 (sub, w, %L1);
OUT_AS2 (mov, w, %H3);
OUT_AS2 (subc, w, %H1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %L1);
OUT_AS2 (sub, w, %L0);
OUT_AS2 (mov, w, %H1);
OUT_AS2 (subc, w, %H0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LTU:
if (imm_sub)
{
if (INTVAL (operands[0]) == 0)
{
OUT_AS2 (mov, w, %H1);
OUT_AS2 (or, w, %L1);
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
OUT_AS2 (mov, w, %L3);
OUT_AS2 (sub, w, %L1);
OUT_AS2 (mov, w, %H3);
OUT_AS2 (subc, w, %H1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %L1);
OUT_AS2 (sub, w, %L0);
OUT_AS2 (mov, w, %H1);
OUT_AS2 (subc, w, %H0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LEU:
if (imm_sub)
{
if ((INTVAL (operands[1]) & 0xffff) == 0xffff)
{
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
OUT_AS2 (mov, w, %L3);
OUT_AS2 (sub, w, %L0);
OUT_AS2 (mov, w, %H3);
OUT_AS2 (subc, w, %H0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %L0);
OUT_AS2 (sub, w, %L1);
OUT_AS2 (mov, w, %H0);
OUT_AS2 (subc, w, %H1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
default:
abort ();
}
break;
case SImode:
switch (code)
{
case EQ:
{
unsigned char a = 0, b = 1, c = 2, d = 3;
if (imm_cmp)
{
a = (INTVAL (operands[1]) >> 24) & 0xff;
b = (INTVAL (operands[1]) >> 16) & 0xff;
c = (INTVAL (operands[1]) >> 8) & 0xff;
d = INTVAL (operands[1]) & 0xff;
}
OUT_AS2 (mov, w, %A1);
if (imm_cmp && (b == a))
{
OUT_AS2 (csne, w, %A0);
OUT_AS2 (cse, w, %B0);
}
else
{
OUT_AS2 (cse, w, %A0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %B1);
OUT_AS2 (cse, w, %B0);
}
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
if (! imm_cmp || (c != b))
OUT_AS2 (mov, w, %C1);
OUT_AS2 (cse, w, %C0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
if (! imm_cmp || (d != c))
OUT_AS2 (mov, w, %D1);
OUT_AS2 (csne, w, %D0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS1 (2:,);
}
break;
case NE:
{
unsigned char a = 0, b = 1, c = 2, d = 3;
if (imm_cmp)
{
a = (INTVAL (operands[1]) >> 24) & 0xff;
b = (INTVAL (operands[1]) >> 16) & 0xff;
c = (INTVAL (operands[1]) >> 8) & 0xff;
d = INTVAL (operands[1]) & 0xff;
}
OUT_AS2 (mov, w, %A1);
if (imm_cmp && (b == a))
{
OUT_AS2 (csne, w, %A0);
OUT_AS2 (cse, w, %B0);
}
else
{
OUT_AS2 (cse, w, %A0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %B1);
OUT_AS2 (cse, w, %B0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
if (! imm_cmp || (c != b))
OUT_AS2 (mov, w, %C1);
if (imm_cmp && (d == c))
{
OUT_AS2 (csne, w, %C0);
OUT_AS2 (cse, w, %D0);
}
else
{
OUT_AS2 (cse, w, %C0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %D1);
OUT_AS2 (cse, w, %D0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GTU:
if (imm_sub)
{
if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
!= 0xffffffff)
{
operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %D0);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %C0);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %B0);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %A0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %D0);
OUT_AS2 (sub, w, %D1);
OUT_AS2 (mov, w, %C0);
OUT_AS2 (subc, w, %C1);
OUT_AS2 (mov, w, %B0);
OUT_AS2 (subc, w, %B1);
OUT_AS2 (mov, w, %A0);
OUT_AS2 (subc, w, %A1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GEU:
if (imm_sub)
{
if (INTVAL (operands[0]) == 0)
{
OUT_AS2 (mov, w, %A1);
OUT_AS2 (or, w, %B1);
OUT_AS2 (or, w, %C1);
OUT_AS2 (or, w, %D1);
OUT_AS1 (snz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %D1);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %C1);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %B1);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %A1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %D1);
OUT_AS2 (sub, w, %D0);
OUT_AS2 (mov, w, %C1);
OUT_AS2 (subc, w, %C0);
OUT_AS2 (mov, w, %B1);
OUT_AS2 (subc, w, %B0);
OUT_AS2 (mov, w, %A1);
OUT_AS2 (subc, w, %A0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LTU:
if (imm_sub)
{
if (INTVAL (operands[0]) == 0)
{
OUT_AS2 (mov, w, %A1);
OUT_AS2 (or, w, %B1);
OUT_AS2 (or, w, %C1);
OUT_AS2 (or, w, %D1);
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %D1);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %C1);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %B1);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %A1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %D1);
OUT_AS2 (sub, w, %D0);
OUT_AS2 (mov, w, %C1);
OUT_AS2 (subc, w, %C0);
OUT_AS2 (mov, w, %B1);
OUT_AS2 (subc, w, %B0);
OUT_AS2 (mov, w, %A1);
OUT_AS2 (subc, w, %A0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LEU:
if (imm_sub)
{
if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
== 0xffffffff)
{
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %D0);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %C0);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %B0);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %A0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %D0);
OUT_AS2 (sub, w, %D1);
OUT_AS2 (mov, w, %C0);
OUT_AS2 (subc, w, %C1);
OUT_AS2 (mov, w, %B0);
OUT_AS2 (subc, w, %B1);
OUT_AS2 (mov, w, %A0);
OUT_AS2 (subc, w, %A1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
default:
abort ();
}
break;
case DImode:
if (GET_CODE (operands[1]) == CONST_INT)
{
const_low = INTVAL (operands[1]);
const_high = (const_low >= 0) - 1;
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
const_low = CONST_DOUBLE_LOW (operands[1]);
const_high = CONST_DOUBLE_HIGH (operands[1]);
}
switch (code)
{
case EQ:
{
unsigned char s = 0, t = 1, u = 2, v = 3;
unsigned char w = 4, x = 5, y = 6, z = 7;
if (optimize_size)
{
if (GET_CODE (operands[0]) == MEM
&& true_regnum (XEXP (operands[0], 0)) == REG_DP)
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2_dp);
OUT_AS1 (call, __cmpdi2_dp);
OUT_AS2 (csne, w, #1);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%<);
OUT_AS1 (push, %Z0%<);
OUT_AS1 (push, %Y0%<);
OUT_AS1 (push, %X0%<);
OUT_AS1 (push, %W0%<);
OUT_AS1 (push, %V0%<);
OUT_AS1 (push, %U0%<);
OUT_AS1 (push, %T0%<);
OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2);
OUT_AS1 (call, __cmpdi2);
OUT_AS2 (csne, w, #1);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
if (imm_cmp)
{
s = (const_high >> 24) & 0xff;
t = (const_high >> 16) & 0xff;
u = (const_high >> 8) & 0xff;
v = const_high & 0xff;
w = (const_low >> 24) & 0xff;
x = (const_low >> 16) & 0xff;
y = (const_low >> 8) & 0xff;
z = const_low & 0xff;
}
OUT_AS2 (mov, w, %S1);
if (imm_cmp && (s == t))
{
OUT_AS2 (csne, w, %S0);
OUT_AS2 (cse, w, %T0);
}
else
{
OUT_AS2 (cse, w, %S0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %T1);
OUT_AS2 (cse, w, %T0);
}
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %U1);
if (imm_cmp && (u == v))
{
OUT_AS2 (csne, w, %U0);
OUT_AS2 (cse, w, %V0);
}
else
{
OUT_AS2 (cse, w, %U0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %V1);
OUT_AS2 (cse, w, %V0);
}
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %W1);
if (imm_cmp && (w == x))
{
OUT_AS2 (csne, w, %W0);
OUT_AS2 (cse, w, %X0);
}
else
{
OUT_AS2 (cse, w, %W0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
OUT_AS2 (mov, w, %X1);
OUT_AS2 (cse, w, %X0);
}
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
if (! imm_cmp || (x != y))
OUT_AS2 (mov, w, %Y1);
OUT_AS2 (cse, w, %Y0);
OUT_AS1 (page, 2f);
OUT_AS1 (jmp, 2f);
if (! imm_cmp || (z != y))
OUT_AS2 (mov, w, %Z1);
OUT_AS2 (csne, w, %Z0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS1 (2:,);
}
}
break;
case NE:
{
unsigned char s = 0, t = 1, u = 2, v = 3;
unsigned char w = 4, x = 5, y = 6, z = 7;
if (optimize_size)
{
if (GET_CODE (operands[0]) == MEM
&& true_regnum (XEXP (operands[0], 0)) == REG_DP)
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2_dp);
OUT_AS1 (call, __cmpdi2_dp);
OUT_AS2 (cse, w, #1);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
OUT_AS1 (push, %Z1%<);
OUT_AS1 (push, %Y1%<);
OUT_AS1 (push, %X1%<);
OUT_AS1 (push, %W1%<);
OUT_AS1 (push, %V1%<);
OUT_AS1 (push, %U1%<);
OUT_AS1 (push, %T1%<);
OUT_AS1 (push, %S1%<);
OUT_AS1 (push, %Z0%<);
OUT_AS1 (push, %Y0%<);
OUT_AS1 (push, %X0%<);
OUT_AS1 (push, %W0%<);
OUT_AS1 (push, %V0%<);
OUT_AS1 (push, %U0%<);
OUT_AS1 (push, %T0%<);
OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
OUT_AS1 (page, __cmpdi2);
OUT_AS1 (call, __cmpdi2);
OUT_AS2 (cse, w, #1);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
if (imm_cmp)
{
s = (const_high >> 24) & 0xff;
t = (const_high >> 16) & 0xff;
u = (const_high >> 8) & 0xff;
v = const_high & 0xff;
w = (const_low >> 24) & 0xff;
x = (const_low >> 16) & 0xff;
y = (const_low >> 8) & 0xff;
z = const_low & 0xff;
}
OUT_AS2 (mov, w, %S1);
if (imm_cmp && (s == t))
{
OUT_AS2 (csne, w, %S0);
OUT_AS2 (cse, w, %T0);
}
else
{
OUT_AS2 (cse, w, %S0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %T1);
OUT_AS2 (cse, w, %T0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %U1);
if (imm_cmp && (u == v))
{
OUT_AS2 (csne, w, %U0);
OUT_AS2 (cse, w, %V0);
}
else
{
OUT_AS2 (cse, w, %U0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %V1);
OUT_AS2 (cse, w, %V0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %W1);
if (imm_cmp && (w == x))
{
OUT_AS2 (csne, w, %W0);
OUT_AS2 (cse, w, %X0);
}
else
{
OUT_AS2 (cse, w, %W0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %X1);
OUT_AS2 (cse, w, %X0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
if (! imm_cmp || (y != x))
OUT_AS2 (mov, w, %Y1);
if (imm_cmp && (z == y))
{
OUT_AS2 (csne, w, %Y0);
OUT_AS2 (cse, w, %Z0);
}
else
{
OUT_AS2 (cse, w, %Y0);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
OUT_AS2 (mov, w, %Z1);
OUT_AS2 (cse, w, %Z0);
}
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
break;
case GTU:
if (imm_sub)
{
if (((const_high & 0xffffffff) != 0xffffffff)
|| ((const_low & 0xffffffff) != 0xffffffff))
{
operands[3] = GEN_INT (const_low + 1);
operands[4] = GEN_INT (const_high
+ (INTVAL (operands[3]) ? 0 : 1));
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %Z0);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %Y0);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %X0);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %W0);
OUT_AS2 (mov, w, %D4);
OUT_AS2 (subc, w, %V0);
OUT_AS2 (mov, w, %C4);
OUT_AS2 (subc, w, %U0);
OUT_AS2 (mov, w, %B4);
OUT_AS2 (subc, w, %T0);
OUT_AS2 (mov, w, %A4);
OUT_AS2 (subc, w, %S0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %Z0);
OUT_AS2 (sub, w, %Z1);
OUT_AS2 (mov, w, %Y0);
OUT_AS2 (subc, w, %Y1);
OUT_AS2 (mov, w, %X0);
OUT_AS2 (subc, w, %X1);
OUT_AS2 (mov, w, %W0);
OUT_AS2 (subc, w, %W1);
OUT_AS2 (mov, w, %V0);
OUT_AS2 (subc, w, %V1);
OUT_AS2 (mov, w, %U0);
OUT_AS2 (subc, w, %U1);
OUT_AS2 (mov, w, %T0);
OUT_AS2 (subc, w, %T1);
OUT_AS2 (mov, w, %S0);
OUT_AS2 (subc, w, %S1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case GEU:
if (imm_sub)
{
HOST_WIDE_INT const_low0;
HOST_WIDE_INT const_high0;
if (GET_CODE (operands[0]) == CONST_INT)
{
const_low0 = INTVAL (operands[0]);
const_high0 = (const_low >= 0) - 1;
}
else if (GET_CODE (operands[0]) == CONST_DOUBLE)
{
const_low0 = CONST_DOUBLE_LOW (operands[0]);
const_high0 = CONST_DOUBLE_HIGH (operands[0]);
}
if (const_high0 == 0 && const_low0 == 0)
{
OUT_AS2 (mov, w, %S1);
OUT_AS2 (or, w, %T1);
OUT_AS2 (or, w, %U1);
OUT_AS2 (or, w, %V1);
OUT_AS2 (or, w, %W1);
OUT_AS2 (or, w, %X1);
OUT_AS2 (or, w, %Y1);
OUT_AS2 (or, w, %Z1);
OUT_AS1 (snz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (const_low0 - 1);
operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %Z1);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %Y1);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %X1);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %W1);
OUT_AS2 (mov, w, %D4);
OUT_AS2 (subc, w, %V1);
OUT_AS2 (mov, w, %C4);
OUT_AS2 (subc, w, %U1);
OUT_AS2 (mov, w, %B4);
OUT_AS2 (subc, w, %T1);
OUT_AS2 (mov, w, %A4);
OUT_AS2 (subc, w, %S1);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %Z1);
OUT_AS2 (sub, w, %Z0);
OUT_AS2 (mov, w, %Y1);
OUT_AS2 (subc, w, %Y0);
OUT_AS2 (mov, w, %X1);
OUT_AS2 (subc, w, %X0);
OUT_AS2 (mov, w, %W1);
OUT_AS2 (subc, w, %W0);
OUT_AS2 (mov, w, %V1);
OUT_AS2 (subc, w, %V0);
OUT_AS2 (mov, w, %U1);
OUT_AS2 (subc, w, %U0);
OUT_AS2 (mov, w, %T1);
OUT_AS2 (subc, w, %T0);
OUT_AS2 (mov, w, %S1);
OUT_AS2 (subc, w, %S0);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LTU:
if (imm_sub)
{
HOST_WIDE_INT const_low0;
HOST_WIDE_INT const_high0;
if (GET_CODE (operands[0]) == CONST_INT)
{
const_low0 = INTVAL (operands[0]);
const_high0 = (const_low >= 0) - 1;
}
else if (GET_CODE (operands[0]) == CONST_DOUBLE)
{
const_low0 = CONST_DOUBLE_LOW (operands[0]);
const_high0 = CONST_DOUBLE_HIGH (operands[0]);
}
if (const_high0 == 0 && const_low0 == 0)
{
OUT_AS2 (mov, w, %S1);
OUT_AS2 (or, w, %T1);
OUT_AS2 (or, w, %U1);
OUT_AS2 (or, w, %V1);
OUT_AS2 (or, w, %W1);
OUT_AS2 (or, w, %X1);
OUT_AS2 (or, w, %Y1);
OUT_AS2 (or, w, %Z1);
OUT_AS1 (sz,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (const_low0 - 1);
operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %Z1);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %Y1);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %X1);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %W1);
OUT_AS2 (mov, w, %D4);
OUT_AS2 (subc, w, %V1);
OUT_AS2 (mov, w, %C4);
OUT_AS2 (subc, w, %U1);
OUT_AS2 (mov, w, %B4);
OUT_AS2 (subc, w, %T1);
OUT_AS2 (mov, w, %A4);
OUT_AS2 (subc, w, %S1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %Z1);
OUT_AS2 (sub, w, %Z0);
OUT_AS2 (mov, w, %Y1);
OUT_AS2 (subc, w, %Y0);
OUT_AS2 (mov, w, %X1);
OUT_AS2 (subc, w, %X0);
OUT_AS2 (mov, w, %W1);
OUT_AS2 (subc, w, %W0);
OUT_AS2 (mov, w, %V1);
OUT_AS2 (subc, w, %V0);
OUT_AS2 (mov, w, %U1);
OUT_AS2 (subc, w, %U0);
OUT_AS2 (mov, w, %T1);
OUT_AS2 (subc, w, %T0);
OUT_AS2 (mov, w, %S1);
OUT_AS2 (subc, w, %S0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
case LEU:
if (imm_sub)
{
if (((const_high & 0xffffffff) == 0xffffffff)
&& ((const_low & 0xffffffff) == 0xffffffff))
{
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
else
{
operands[3] = GEN_INT (const_low + 1);
operands[4] = GEN_INT (const_high
+ (INTVAL (operands[3]) ? 0 : 1));
OUT_AS2 (mov, w, %D3);
OUT_AS2 (sub, w, %Z0);
OUT_AS2 (mov, w, %C3);
OUT_AS2 (subc, w, %Y0);
OUT_AS2 (mov, w, %B3);
OUT_AS2 (subc, w, %X0);
OUT_AS2 (mov, w, %A3);
OUT_AS2 (subc, w, %W0);
OUT_AS2 (mov, w, %D4);
OUT_AS2 (subc, w, %V0);
OUT_AS2 (mov, w, %C4);
OUT_AS2 (subc, w, %U0);
OUT_AS2 (mov, w, %B4);
OUT_AS2 (subc, w, %T0);
OUT_AS2 (mov, w, %A4);
OUT_AS2 (subc, w, %S0);
OUT_AS1 (sc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
}
else
{
OUT_AS2 (mov, w, %Z0);
OUT_AS2 (sub, w, %Z1);
OUT_AS2 (mov, w, %Y0);
OUT_AS2 (subc, w, %Y1);
OUT_AS2 (mov, w, %X0);
OUT_AS2 (subc, w, %X1);
OUT_AS2 (mov, w, %W0);
OUT_AS2 (subc, w, %W1);
OUT_AS2 (mov, w, %V0);
OUT_AS2 (subc, w, %V1);
OUT_AS2 (mov, w, %U0);
OUT_AS2 (subc, w, %U1);
OUT_AS2 (mov, w, %T0);
OUT_AS2 (subc, w, %T1);
OUT_AS2 (mov, w, %S0);
OUT_AS2 (subc, w, %S1);
OUT_AS1 (snc,);
OUT_AS1 (page, %2);
OUT_AS1 (jmp, %2);
}
break;
default:
abort ();
}
break;
default:
abort ();
}
#undef operands
return "";
}
void
asm_output_char(file, value)
FILE *file;
rtx value;
{
fprintf (file, "\t.byte ");
output_addr_const (file, value);
fprintf (file, "\n");
}
void
asm_output_byte (file,value)
FILE *file;
int value;
{
fprintf (file, "\t.byte 0x%x\n",value & 0xff);
}
void
asm_output_short (file, value)
FILE *file;
rtx value;
{
fprintf (file, "\t.word ");
output_addr_const (file, (value));
fprintf (file, "\n");
}
void
asm_output_float (file, n)
FILE *file;
REAL_VALUE_TYPE n;
{
long val;
char dstr[100];
REAL_VALUE_TO_TARGET_SINGLE (n, val);
real_to_decimal (dstr, &n, sizeof (dstr), 0, 1);
fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
}
void
unique_section (decl, reloc)
tree decl;
int reloc ATTRIBUTE_UNUSED;
{
int len;
const char *name;
char *string;
const char *prefix;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = (* targetm.strip_name_encoding) (name);
if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (flag_function_sections)
prefix = ".text.";
else
prefix = ".text";
}
else
abort ();
if (flag_function_sections)
{
len = strlen (name) + strlen (prefix);
string = alloca (len + 1);
sprintf (string, "%s%s", prefix, name);
DECL_SECTION_NAME (decl) = build_string (len, string);
}
}
void
asm_output_section_name(file, decl, name, reloc)
FILE *file;
tree decl ATTRIBUTE_UNUSED;
const char *name;
int reloc ATTRIBUTE_UNUSED;
{
fprintf (file, ".section %s\n", name);
}
enum reg_class
class_likely_spilled_p(c)
int c;
{
return (c == IP_REGS
|| c == IPL_REGS
|| c == IPH_REGS
|| c == DP_SP_REGS
|| c == SP_REGS
|| c == DP_REGS
|| c == DPL_REGS
|| c == DPH_REGS
|| c == PTR_REGS);
}
const struct attribute_spec ip2k_attribute_table[] =
{
{ "progmem", 0, 0, false, false, false, ip2k_handle_progmem_attribute },
{ "naked", 0, 0, true, false, false, ip2k_handle_fndecl_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
static tree
ip2k_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name;
tree args ATTRIBUTE_UNUSED;
int flags ATTRIBUTE_UNUSED;
bool *no_add_attrs;
{
if (DECL_P (*node))
{
if (TREE_CODE (*node) == TYPE_DECL)
{
tree type = TREE_TYPE (*node);
tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
tree newtype = build_type_attribute_variant (type, attr);
TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
TREE_TYPE (*node) = newtype;
*no_add_attrs = true;
}
else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
{
if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
{
warning ("only initialized variables can be placed into "
"program memory area");
*no_add_attrs = true;
}
}
else
{
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
}
return NULL_TREE;
}
static tree
ip2k_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name;
tree args ATTRIBUTE_UNUSED;
int flags ATTRIBUTE_UNUSED;
bool *no_add_attrs;
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning ("`%s' attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
void
encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
if (! DECL_P (decl))
return;
if (TREE_CODE (decl) == FUNCTION_DECL)
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
}
void
asm_file_start (file)
FILE *file;
{
output_file_directive (file, main_input_filename);
commands_in_prologues = 0;
commands_in_epilogues = 0;
}
void
asm_file_end (file)
FILE *file;
{
fprintf
(file,
"/* File %s: prologues %3d, epilogues %3d */\n",
main_input_filename, commands_in_prologues, commands_in_epilogues);
}
int
default_rtx_costs (x, code, outer_code)
rtx x;
enum rtx_code code;
enum rtx_code outer_code;
{
enum machine_mode mode = GET_MODE (x);
int extra_cost = 0;
int total;
switch (code)
{
case MEM:
return ip2k_address_cost (XEXP (x, 0));
case ROTATE:
case ROTATERT:
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
int val = INTVAL (XEXP (x, 1));
int cost;
cost = COSTS_N_INSNS (abs (val) % 8);
cost += rtx_cost (XEXP (x, 0), code);
cost *= (GET_MODE_SIZE (mode) + 1);
if (code == ASHIFT)
cost += COSTS_N_INSNS (2);
return cost;
}
total = rtx_cost (XEXP (x, 0), code);
total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 8);
return total;
case MINUS:
case PLUS:
case AND:
case XOR:
case IOR:
total = rtx_cost (XEXP (x, 0), code)
+ rtx_cost (XEXP (x, 1), code);
total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3);
return total;
case MOD:
case DIV:
if (mode == QImode)
return COSTS_N_INSNS (20);
if (mode == HImode)
return COSTS_N_INSNS (60);
else if (mode == SImode)
return COSTS_N_INSNS (180);
else
return COSTS_N_INSNS (540);
case MULT:
if (mode == QImode)
return COSTS_N_INSNS (4);
if (mode == HImode)
return COSTS_N_INSNS (12);
if (mode == SImode)
return COSTS_N_INSNS (36);
else
return COSTS_N_INSNS (108);
case NEG:
case SIGN_EXTEND:
extra_cost = COSTS_N_INSNS (GET_MODE_SIZE (mode));
case NOT:
case COMPARE:
case ABS:
total = rtx_cost (XEXP (x, 0), code);
return total + extra_cost + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 2);
case TRUNCATE:
case ZERO_EXTEND:
if (outer_code == SET)
return rtx_cost (XEXP (x, 0), code)
+ COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3 / 2);
else
return -(COSTS_N_INSNS (GET_MODE_SIZE (mode)) / 2);
case IF_THEN_ELSE:
return rtx_cost (XEXP (x, 0), code)
+ COSTS_N_INSNS (2);
case EQ:
case NE:
case LTU:
case GTU:
case LEU:
case GEU:
case LT:
case GT:
case LE:
case GE:
return rtx_cost (XEXP (x, 0), code)
+ rtx_cost (XEXP (x, 1), code);
default:
return COSTS_N_INSNS (4);
}
}
int
ip2k_address_cost (x)
rtx x;
{
switch (legitimate_address_p (VOIDmode, x, 0))
{
case 'S':
return 8;
case 'R':
return 8;
case 'L':
return 0;
case 'C':
return 4;
default:
return 1000;
}
}
#ifdef IP2K_MD_REORG_PASS
static void
mdr_resequence_xy_yx (first_insn)
rtx first_insn;
{
rtx insn;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
rtx set;
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if ((GET_CODE (XEXP (set, 0)) == REG
|| GET_CODE (XEXP (set, 0)) == MEM)
&& (GET_CODE (XEXP (set, 1)) == ASHIFT
|| GET_CODE (XEXP (set, 1)) == ASHIFTRT
|| GET_CODE (XEXP (set, 1)) == LSHIFTRT
|| GET_CODE (XEXP (set, 1)) == XOR
|| GET_CODE (XEXP (set, 1)) == IOR
|| GET_CODE (XEXP (set, 1)) == AND
|| GET_CODE (XEXP (set, 1)) == PLUS
|| GET_CODE (XEXP (set, 1)) == MINUS
|| GET_CODE (XEXP (set, 1)) == MULT))
{
rtx set2;
rtx next_insn;
next_insn = next_nonnote_insn (insn);
if (! next_insn)
continue;
if (GET_CODE (next_insn) != INSN)
continue;
set2 = ((GET_CODE (PATTERN (next_insn)) == SET)
? PATTERN (next_insn) : NULL_RTX);
if (set2 == NULL_RTX)
continue;
if ((GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
|| GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM)
&& rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 0))
&& rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
{
rtx next2_insn;
rtx b_insn;
b_insn = gen_rtx_SET (VOIDmode,
XEXP (XEXP (set, 1), 0),
gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
GET_MODE (XEXP (set, 0)),
XEXP (XEXP (set, 1), 0),
XEXP (XEXP (set, 1), 1)));
emit_insn_before (b_insn, insn);
b_insn = gen_rtx_SET (GET_MODE (XEXP (set, 0)), XEXP (set, 0),
XEXP (XEXP (set, 1), 0));
next2_insn = emit_insn_before (b_insn, insn);
delete_insn (insn);
delete_insn (next_insn);
insn = next2_insn;
continue;
}
if (GET_RTX_CLASS (GET_CODE (XEXP (set, 1))) == 'c'
&& (GET_CODE (XEXP (XEXP (set, 1), 1)) == REG
|| GET_CODE (XEXP (XEXP (set, 1), 1)) == MEM)
&& rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 1))
&& rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
{
rtx rtx_ee;
rtx next2_insn;
int swap_args;
swap_args = (GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
|| GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM);
rtx_ee = gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
GET_MODE (XEXP (set, 0)),
XEXP (XEXP (set, 1), swap_args ? 1 : 0),
XEXP (XEXP (set, 1),
swap_args ? 0 : 1));
emit_insn_before (gen_rtx_SET (VOIDmode,
XEXP (XEXP (set, 1), 1),
rtx_ee),
insn);
next2_insn = emit_insn_before (gen_rtx_SET
(GET_MODE (XEXP (set, 0)),
XEXP (set, 0),
XEXP (XEXP (set, 1), 1)),
insn);
delete_insn (insn);
delete_insn (next_insn);
insn = next2_insn;
}
}
}
}
static void
mdr_pres_replace_and_recurse (orig, with, insn)
rtx orig;
rtx with;
rtx insn;
{
enum machine_mode new_mode;
validate_replace_rtx (orig, with, insn);
switch (GET_MODE (orig))
{
case DImode:
case DFmode:
new_mode = SImode;
break;
case SImode:
case SFmode:
new_mode = HImode;
break;
case HImode:
new_mode = QImode;
break;
default:
return;
}
mdr_pres_replace_and_recurse (ip2k_get_low_half (orig, new_mode),
ip2k_get_low_half (with, new_mode),
insn);
mdr_pres_replace_and_recurse (ip2k_get_high_half (orig, new_mode),
ip2k_get_high_half (with, new_mode),
insn);
}
static void
mdr_propagate_reg_equivs_sequence (first_insn, orig, equiv)
rtx first_insn;
rtx orig;
rtx equiv;
{
rtx try_insn;
rtx try_equiv = equiv;
for (try_insn = next_nonnote_insn (first_insn);
try_insn; try_insn = next_nonnote_insn (try_insn))
{
rtx pattern;
if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
continue;
pattern = PATTERN (try_insn);
if (GET_CODE (pattern) == PARALLEL)
{
int j;
for (j = 0; j < XVECLEN (pattern, 0); j++)
{
rtx px = XVECEXP (pattern, 0, j);
if (GET_CODE (px) == SET)
if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (px, 0),
REGNO (orig),
GET_MODE_SIZE (GET_MODE (orig))))
return;
}
}
else if (GET_CODE (pattern) == SET)
{
if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (pattern, 0),
REGNO (orig),
GET_MODE_SIZE (GET_MODE (orig))))
return;
}
}
for (try_insn = next_nonnote_insn (first_insn); try_insn;
try_insn = next_nonnote_insn (try_insn))
{
rtx set;
rtx new_equiv = NULL_RTX;
if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
{
try_equiv = equiv;
continue;
}
set = ((GET_CODE (PATTERN (try_insn)) == SET)
? PATTERN (try_insn) : NULL_RTX);
if (set == NULL_RTX)
continue;
if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& REG_P (XEXP (XEXP (XEXP (set, 0), 0), 0))
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP)
{
HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (try_equiv, 0), 1))
+ GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
new_equiv = gen_rtx_MEM (GET_MODE (try_equiv),
gen_rtx_PLUS (Pmode,
gen_rtx_REG (HImode, REG_SP),
GEN_INT (disp)));
}
mdr_pres_replace_and_recurse (orig, try_equiv, try_insn);
if (new_equiv != NULL_RTX)
try_equiv = new_equiv;
}
}
static void
mdr_propagate_reg_equivs (first_insn)
rtx first_insn;
{
rtx insn;
rtx set;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if (REG_P (XEXP (set, 0))
&& REGNO (XEXP (set, 0)) >= 0x88
&& GET_CODE (XEXP (set, 1)) == MEM
&& GET_CODE (XEXP (XEXP (set, 1), 0)) == PLUS
&& REG_P (XEXP (XEXP (XEXP (set, 1), 0), 0))
&& REGNO (XEXP (XEXP (XEXP (set, 1), 0), 0)) == REG_SP
&& find_reg_note (insn, REG_EQUIV, NULL_RTX))
{
mdr_propagate_reg_equivs_sequence (insn, XEXP (set, 0),
XEXP (set, 1));
}
}
}
struct dpre_jump_targets
{
int target;
int reach_count;
int touch_count;
rtx dp_equiv;
};
struct dpre_jump_targets *ip2k_dpre_jump_targets;
static int
track_dp_reload (insn, dp_current, dp_current_ok, modifying)
rtx insn;
rtx *dp_current;
int dp_current_ok;
int modifying;
{
rtx set;
if (GET_CODE (insn) != INSN)
{
*dp_current = NULL_RTX;
return 1;
}
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
{
*dp_current = NULL_RTX;
return 1;
}
if (*dp_current != NULL_RTX
&& GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
&& (GET_CODE (XEXP (set, 1)) == PLUS
|| GET_CODE (XEXP (set, 1)) == MINUS)
&& GET_CODE (*dp_current) != SYMBOL_REF
&& GET_CODE (*dp_current) != LABEL_REF
&& GET_CODE (*dp_current) != CONST)
{
if (modifying)
validate_replace_rtx (*dp_current, gen_rtx_REG (HImode, REG_DP), insn);
}
if (GET_CODE (XEXP (set, 0)) == REG
&& REGNO (XEXP (set, 0)) == REG_DP
&& GET_MODE (XEXP (set, 0)) == HImode)
{
if (*dp_current != NULL_RTX
&& rtx_equal_p (XEXP (set, 1), *dp_current))
{
if (modifying)
delete_insn (insn);
}
else
{
if (*dp_current != NULL_RTX
&& GET_CODE (*dp_current) != SYMBOL_REF
&& GET_CODE (*dp_current) != LABEL_REF
&& GET_CODE (*dp_current) != CONST
&& modifying)
validate_replace_rtx (*dp_current, XEXP (set, 0), insn);
if (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2))
{
*dp_current = XEXP (set, 1);
return 1;
}
else
{
*dp_current = NULL_RTX;
return 1;
}
}
}
else if (GET_CODE (XEXP (set, 0)) == REG
&& (REGNO (XEXP (set, 0)) == REG_DPL
|| REGNO (XEXP (set, 0)) == REG_DPH))
{
*dp_current = NULL_RTX;
return 1;
}
else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
&& *dp_current != NULL_RTX
&& !ip2k_xexp_not_uses_reg_p (*dp_current, REG_SP, 2))
{
if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
&& GET_CODE (*dp_current) == MEM
&& GET_CODE (XEXP (*dp_current, 0)) == PLUS)
{
HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (*dp_current, 0), 1))
+ GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
*dp_current = gen_rtx_MEM (HImode,
gen_rtx_PLUS (Pmode,
gen_rtx_REG(HImode, REG_SP),
GEN_INT (disp)));
return 1;
}
if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (*dp_current) == MEM)
{
int dp_cur_sp_offs = INTVAL (XEXP (XEXP (*dp_current, 0), 1));
int set_sp_offs = INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1));
if (abs (dp_cur_sp_offs - set_sp_offs) < 2)
{
*dp_current = NULL_RTX;
return 1;
}
}
}
else if (GET_CODE (XEXP (set, 0)) == REG
&& *dp_current != NULL_RTX
&& !ip2k_xexp_not_uses_reg_p (*dp_current, REGNO (XEXP (set, 0)),
GET_MODE_SIZE (GET_MODE (XEXP (set,
0)))))
{
*dp_current = NULL_RTX;
}
return dp_current_ok;
}
static void
mdr_try_dp_reload_elim (first_insn)
rtx first_insn;
{
rtx insn;
struct dpre_jump_targets *djt;
rtx dp_current;
int incomplete_scan;
int last_incomplete_scan;
ip2k_dpre_jump_targets
= (struct dpre_jump_targets *) xcalloc (get_max_uid (),
sizeof (struct dpre_jump_targets));
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
djt->target = 1;
djt->reach_count = LABEL_NUSES (insn);
djt->touch_count = 0;
djt->dp_equiv = NULL_RTX;
if (! prev_nonnote_insn (insn)
|| (prev_nonnote_insn (insn)
&& GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
djt->reach_count++;
}
}
incomplete_scan = -1;
do
{
int dp_current_ok = 0;
last_incomplete_scan = incomplete_scan;
dp_current = NULL_RTX;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
if (djt->touch_count == djt->reach_count)
{
dp_current = djt->dp_equiv;
dp_current_ok = 1;
continue;
}
if (dp_current_ok
&& (! prev_nonnote_insn (insn)
|| (prev_nonnote_insn (insn)
&& GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
{
if (djt->touch_count == 0)
djt->dp_equiv = dp_current;
if (djt->touch_count < djt->reach_count)
{
djt->touch_count++;
if (! rtx_equal_p (djt->dp_equiv, dp_current))
{
djt->dp_equiv = NULL_RTX;
dp_current = NULL_RTX;
dp_current_ok = 1;
}
}
}
if (djt->touch_count < djt->reach_count)
{
dp_current = NULL_RTX;
dp_current_ok = 0;
}
continue;
}
if (GET_CODE (insn) == JUMP_INSN)
{
if (dp_current_ok)
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) == ADDR_VEC)
{
int i;
int len = XVECLEN (pat, 0);
for (i = 0; i < len; i++)
{
rtx vec_insn = XEXP (XVECEXP (pat, 0, i), 0);
djt = &ip2k_dpre_jump_targets [INSN_UID (vec_insn)];
if (djt->touch_count == 0)
djt->dp_equiv = dp_current;
if (djt->touch_count < djt->reach_count)
{
djt->touch_count++;
if (! rtx_equal_p (djt->dp_equiv, dp_current))
djt->dp_equiv = NULL_RTX;
}
}
}
else if (JUMP_LABEL (insn))
{
rtx j_insn = JUMP_LABEL (insn);
djt = &ip2k_dpre_jump_targets[INSN_UID (j_insn)];
if (djt->touch_count == 0)
djt->dp_equiv = dp_current;
if (djt->touch_count < djt->reach_count)
{
djt->touch_count++;
if (! rtx_equal_p (djt->dp_equiv, dp_current))
djt->dp_equiv = NULL_RTX;
}
}
}
continue;
}
dp_current_ok = track_dp_reload (insn, &dp_current,
dp_current_ok, 0);
}
incomplete_scan = 0;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
if (djt->touch_count != djt->reach_count)
{
incomplete_scan += (djt->reach_count - djt->touch_count);
djt->dp_equiv = NULL_RTX;
djt->touch_count = 0;
}
}
}
}
while (incomplete_scan && incomplete_scan != last_incomplete_scan);
dp_current = NULL_RTX;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == JUMP_INSN)
continue;
if (GET_CODE (insn) == CODE_LABEL)
{
djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
dp_current = djt->dp_equiv;
continue;
}
track_dp_reload (insn, &dp_current, 1, 1);
}
free (ip2k_dpre_jump_targets);
}
static void
mdr_try_move_dp_reload (first_insn)
rtx first_insn;
{
rtx insn;
rtx set;
rtx orig_first;
orig_first = first_insn;
first_insn = next_nonnote_insn (first_insn);
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if (GET_CODE (XEXP (set, 0)) == REG
&& REGNO (XEXP (set, 0)) == REG_DP
&& GET_MODE (XEXP (set, 0)) == HImode)
{
int try_again;
rtx try_insn = insn;
do
{
rtx rewind;
rtx check;
try_again = 0;
rewind = prev_nonnote_insn (try_insn);
if (rewind != orig_first && rewind != NULL_RTX
&& GET_CODE (rewind) == INSN)
{
check = ((GET_CODE (PATTERN (rewind)) == SET)
? PATTERN (rewind) : NULL_RTX);
if (check != NULL_RTX
&& ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 0))
&& ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 1)))
{
if (GET_CODE (XEXP (check, 0)) == REG
&& REGNO (XEXP (check, 0)) != REG_DPH
&& REGNO (XEXP (check, 0)) != REG_DPL
&& (ip2k_composite_xexp_not_uses_reg_p
(XEXP (check, 1), REG_DP, 2))
&& (ip2k_composite_xexp_not_uses_reg_p
(XEXP (set, 1),
REGNO (XEXP (check, 0)),
GET_MODE_SIZE (GET_MODE (XEXP (check, 0))))))
{
emit_insn_before (set, rewind);
if (try_insn == insn)
insn = prev_nonnote_insn (insn);
delete_insn (try_insn);
try_insn = prev_nonnote_insn (rewind);
try_again = 1;
}
else if (GET_CODE (XEXP (set, 1)) == REG
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 1), REG_DP, 2)
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REG_DP, 2)
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REGNO (XEXP (set, 1)),
GET_MODE_SIZE (GET_MODE (XEXP (set, 1)))))
{
emit_insn_before (set, rewind);
if (try_insn == insn)
insn = prev_nonnote_insn (insn);
delete_insn (try_insn);
try_insn = prev_nonnote_insn (rewind);
try_again = 1;
}
}
}
}
while (try_again && try_insn);
}
}
}
#endif
static int
ip2k_check_can_adjust_stack_ref (x, offset)
rtx x;
int offset;
{
if (GET_RTX_CLASS (GET_CODE (x)) == '2'
|| GET_RTX_CLASS (GET_CODE (x)) == 'c')
return (ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset)
&& ip2k_check_can_adjust_stack_ref (XEXP (x, 1), offset));
if (GET_RTX_CLASS (GET_CODE (x)) == '1')
return ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset);
switch (GET_CODE (x))
{
case REG:
return (REGNO (x) != REG_SPH && REGNO (x) != REG_SPL);
case MEM:
if (GET_CODE (XEXP (x, 0)) != PLUS)
return 1;
if (GET_CODE (XEXP (XEXP (x, 0), 0)) != REG)
return 1;
if (REGNO (XEXP (XEXP (x, 0), 0)) != REG_SP)
return 1;
return (INTVAL (XEXP (XEXP (x, 0), 1))
+ offset <= (128 - 2 * GET_MODE_SIZE (GET_MODE (x))));
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
return 1;
default:
return 0;
}
}
static void
ip2k_adjust_stack_ref (x, offset)
rtx *x;
int offset;
{
if (GET_RTX_CLASS (GET_CODE (*x)) == '2'
|| GET_RTX_CLASS (GET_CODE (*x)) == 'c')
{
ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
ip2k_adjust_stack_ref (&XEXP (*x, 1), offset);
return;
}
if (GET_RTX_CLASS (GET_CODE (*x)) == '1')
{
ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
return;
}
switch (GET_CODE (*x))
{
case MEM:
if (GET_CODE (XEXP (*x, 0)) != PLUS)
return;
if (GET_CODE (XEXP (XEXP (*x, 0), 0)) != REG)
return;
if (REGNO (XEXP (XEXP (*x, 0), 0)) != REG_SP)
return;
*x = copy_rtx (*x);
XEXP (XEXP (*x, 0), 1) = GEN_INT (INTVAL (XEXP (XEXP (*x, 0), 1))
+ offset);
break;
default:
break;
}
}
#ifdef IP2K_MD_REORG_PASS
static void
mdr_try_move_pushes (first_insn)
rtx first_insn;
{
rtx insn;
rtx set;
rtx orig_first;
orig_first = first_insn;
first_insn = next_nonnote_insn (first_insn);
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
&& GET_CODE (XEXP (set, 1)) == REG)
{
rtx try_insn = insn;
unsigned int regno = REGNO (XEXP (set, 1));
int reg_range = GET_MODE_SIZE (GET_MODE (XEXP (set, 1)));
while (1)
{
rtx rewind;
rtx check;
rewind = prev_nonnote_insn (try_insn);
if (rewind == orig_first || rewind == NULL_RTX
|| GET_CODE (rewind) != INSN)
break;
check = (GET_CODE (PATTERN (rewind)) == SET) ? PATTERN (rewind) : NULL_RTX;
if (check == NULL_RTX)
break;
if (! ip2k_check_can_adjust_stack_ref (XEXP (check, 0),
reg_range)
|| ! ip2k_check_can_adjust_stack_ref (XEXP (check, 1),
reg_range))
break;
if (GET_CODE (XEXP (check, 0)) == MEM
&& GET_CODE (XEXP (XEXP (check, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG_SP)
break;
if (GET_CODE (XEXP (check, 0)) == REG)
{
unsigned int check_reg = REGNO (XEXP (check, 0));
int check_reg_range = GET_MODE_SIZE (GET_MODE (XEXP (check,
0)));
if (check_reg == regno
&& check_reg_range == reg_range
&& ((GET_CODE (XEXP (check, 1)) == REG
|| (GET_CODE (XEXP (check, 1)) == MEM
&& (GET_MODE (XEXP (check, 1)) != HImode
|| ip2k_xexp_not_uses_reg_for_mem (XEXP (check, 1), REG_IP))))))
{
switch (check_reg_range)
{
case 1:
emit_insn_before (gen_movqi (XEXP (set, 0),
XEXP (check, 1)),
rewind);
delete_insn (try_insn);
break;
case 2:
emit_insn_before (gen_movhi (XEXP (set, 0),
XEXP (check, 1)),
rewind);
delete_insn (try_insn);
break;
case 4:
emit_insn_before (gen_movsi (XEXP (set, 0),
XEXP (check, 1)),
rewind);
delete_insn (try_insn);
break;
case 8:
emit_insn_before (gen_movdi (XEXP (set, 0),
XEXP (check, 1)),
rewind);
delete_insn (try_insn);
break;
}
ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
try_insn = prev_nonnote_insn (rewind);
break;
}
if ((check_reg == REG_SPL)
|| (check_reg == REG_SPH)
|| (((regno <= check_reg)
&& (regno + reg_range - 1) >= check_reg)
|| ((regno <= (check_reg + check_reg_range - 1))
&& ((regno + reg_range - 1)
>= (check_reg + check_reg_range - 1)))))
break;
}
emit_insn_before (set, rewind);
delete_insn (try_insn);
ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
try_insn = prev_nonnote_insn (rewind);
}
}
}
}
static void
mdr_try_propagate_clr_sequence (first_insn, regno)
rtx first_insn;
unsigned int regno;
{
rtx try_insn;
for (try_insn = next_nonnote_insn (first_insn); try_insn;
try_insn = next_nonnote_insn (try_insn))
{
rtx new_insn = NULL_RTX;
rtx set2;
if (GET_CODE (try_insn) == JUMP_INSN)
continue;
if (GET_CODE (try_insn) != INSN)
break;
set2 = ((GET_CODE (PATTERN (try_insn)) == SET)
? PATTERN (try_insn) : NULL_RTX);
if (set2 == NULL_RTX)
continue;
if (GET_CODE (XEXP (set2, 1)) == AND
&& ((GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
|| (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 1)) == regno)))
{
rtx remove_insn = try_insn;
try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
const0_rtx), try_insn);
delete_insn (remove_insn);
}
else if (GET_CODE (XEXP (set2, 1)) == IOR
&& GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
{
rtx remove_insn = try_insn;
try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
XEXP (XEXP (set2, 1), 1)),
try_insn);
delete_insn (remove_insn);
}
else if (GET_CODE (XEXP (set2, 1)) == IOR
&& GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
{
rtx remove_insn = try_insn;
try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
XEXP (XEXP (set2, 1), 0)),
try_insn);
delete_insn (remove_insn);
}
else if (GET_CODE (XEXP (set2, 1)) == XOR
&& GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
{
rtx remove_insn = try_insn;
try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
XEXP (XEXP (set2, 1), 1)),
try_insn);
delete_insn (remove_insn);
}
else if (GET_CODE (XEXP (set2, 1)) == XOR
&& GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
&& REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
{
rtx remove_insn = try_insn;
try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
XEXP (XEXP (set2, 1), 0)),
try_insn);
delete_insn (remove_insn);
}
if (GET_CODE (XEXP (set2, 0)) == REG)
{
int reg2_range = GET_MODE_SIZE (GET_MODE (XEXP (set2, 0)));
unsigned int regno2 = REGNO (XEXP (set2, 0));
if (reg2_range == 1
&& regno == regno2
&& GET_CODE (XEXP (set2, 1)) == CONST_INT)
{
int iv = INTVAL (XEXP (set2, 1));
if (iv == 0xff)
iv = -1;
if (iv == 1 || iv == -1)
{
new_insn = gen_rtx_SET (QImode, XEXP (set2, 0),
gen_rtx_PLUS (QImode, XEXP (set2, 0),
GEN_INT (iv)));
new_insn = emit_insn_before (new_insn, try_insn);
delete_insn (try_insn);
try_insn = new_insn;
}
break;
}
if ((regno >= regno2) && (regno <= regno2 + reg2_range - 1))
break;
if (GET_CODE (XEXP (set2, 1)) == REG
&& REGNO (XEXP (set2, 1)) == regno)
{
new_insn = emit_insn_before (gen_rtx_SET (QImode,
XEXP (set2, 0),
const0_rtx),
try_insn);
delete_insn (try_insn);
try_insn = new_insn;
}
}
if (GET_CODE (XEXP (set2, 0)) == CC0)
{
if (GET_CODE (XEXP (set2, 1)) == REG
&& GET_MODE_SIZE (GET_MODE (XEXP (set2, 1))) == 2
&& REGNO (XEXP (set2, 1)) == regno)
{
new_insn = gen_rtx_SET (VOIDmode, gen_rtx (CC0, VOIDmode),
gen_rtx_REG(QImode, regno + 1));
new_insn = emit_insn_before (new_insn, try_insn);
}
else if (GET_CODE (XEXP (set2, 1)) == COMPARE
&& GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
&& GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
&& REGNO (XEXP (XEXP (set2, 1), 0)) == regno
&& GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (set2, 1), 1)) >= 0
&& INTVAL (XEXP (XEXP (set2, 1), 1)) < 256)
{
new_insn = gen_rtx_SET (VOIDmode, cc0_rtx,
gen_rtx_COMPARE(QImode,
gen_rtx_REG (QImode,
regno + 1),
XEXP (XEXP (set2, 1),
1)));
new_insn = emit_insn_before (new_insn, try_insn);
}
if (new_insn != NULL_RTX)
{
delete_insn (try_insn);
try_insn = new_insn;
if (GET_CODE (next_nonnote_insn (try_insn)) == JUMP_INSN)
{
rtx set3;
try_insn = next_nonnote_insn (try_insn);
set3 = ((GET_CODE (PATTERN (try_insn)) == SET)
? PATTERN (try_insn) : NULL_RTX);
if (set3 == NULL_RTX)
continue;
if (LABEL_NUSES (JUMP_LABEL (try_insn)) == 1)
mdr_try_propagate_clr_sequence (JUMP_LABEL (try_insn),
regno);
if (GET_CODE (XEXP (set3, 0)) == PC
&& GET_CODE (XEXP (set3, 1)) == IF_THEN_ELSE
&& (GET_CODE (XEXP (XEXP (set3, 1), 0)) == GT
|| GET_CODE (XEXP (XEXP (set3, 1), 0)) == GE
|| GET_CODE (XEXP (XEXP (set3, 1), 0)) == LT
|| GET_CODE (XEXP (XEXP (set3, 1), 0)) == LE)
&& GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 0)) == CC0
&& (GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 1))
== CONST_INT)
&& GET_CODE (XEXP (XEXP (set3, 1), 1)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (set3, 1), 2)) == PC)
{
enum rtx_code code;
rtx new_if;
rtx cmp;
code = GET_CODE (XEXP (XEXP (set3, 1), 0));
cmp = gen_rtx_fmt_ee ((code == GT
? GTU
: (code == GE
? GEU
: (code == LT ? LTU : LEU))),
VOIDmode,
XEXP (XEXP (XEXP (set3, 1), 0), 0),
XEXP (XEXP (XEXP (set3, 1), 0),
1));
new_if
= gen_rtx_SET (GET_MODE (set3),
pc_rtx,
gen_rtx_IF_THEN_ELSE
(GET_MODE (XEXP (set3, 1)), cmp,
XEXP (XEXP (set3, 1), 1),
XEXP (XEXP (set3, 1), 2)));
new_insn = emit_jump_insn_before (new_if, try_insn);
LABEL_NUSES (JUMP_LABEL (try_insn))++;
delete_insn (try_insn);
try_insn = new_insn;
}
}
}
}
else if (GET_CODE (XEXP (set2, 1)) == PLUS
&& GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
&& GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
&& REGNO (XEXP (XEXP (set2, 1), 0)) == regno
&& (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
|| GET_CODE (XEXP (XEXP (set2, 1), 1)) == MEM
|| GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
|| GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST
|| GET_CODE (XEXP (XEXP (set2, 1), 1)) == SYMBOL_REF))
{
rtx extend = gen_rtx_ZERO_EXTEND (HImode,
gen_rtx_REG (QImode, regno + 1));
new_insn = gen_rtx_SET (HImode, XEXP (set2, 0),
gen_rtx_PLUS (HImode, extend,
XEXP (XEXP (set2, 1), 1)));
new_insn = emit_insn_before (new_insn, try_insn);
delete_insn (try_insn);
try_insn = new_insn;
}
else if (GET_CODE (XEXP (set2, 1)) == PLUS
&& GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
&& GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 1))) == 2
&& REGNO (XEXP (XEXP (set2, 1), 1)) == regno
&& (GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
|| GET_CODE (XEXP (XEXP (set2, 1), 0)) == MEM
|| GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST_INT
|| GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST
|| GET_CODE (XEXP (XEXP (set2, 1), 0)) == SYMBOL_REF))
{
rtx t_src = gen_rtx_PLUS (HImode,
gen_rtx_ZERO_EXTEND (HImode,
gen_rtx_REG (QImode,
regno
+ 1)),
XEXP (XEXP (set2, 1), 0));
new_insn = emit_insn_before (gen_rtx_SET (HImode, XEXP (set2, 0),
t_src),
try_insn);
delete_insn (try_insn);
try_insn = new_insn;
}
}
}
static void
mdr_try_propagate_clr (first_insn)
rtx first_insn;
{
rtx insn;
rtx set;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if (GET_CODE (XEXP (set, 0)) == REG
&& GET_CODE (XEXP (set, 1)) == CONST_INT
&& GET_MODE_SIZE (GET_MODE (XEXP (set, 0))) == 1
&& INTVAL (XEXP (set, 1)) == 0)
{
mdr_try_propagate_clr_sequence (insn, REGNO (XEXP (set, 0)));
}
}
}
#endif
static int
ip2k_xexp_not_uses_reg_for_mem (x, regno)
rtx x;
unsigned int regno;
{
if (regno & 1)
regno &= 0xfffffffe;
if (GET_RTX_CLASS (GET_CODE (x)) == 'b')
return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
&& ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno)
&& ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 2), regno));
if (GET_RTX_CLASS (GET_CODE (x)) == '2'
|| GET_RTX_CLASS (GET_CODE (x)) == 'c'
|| GET_RTX_CLASS (GET_CODE (x)) == '<')
return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
&& ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno));
if (GET_RTX_CLASS (GET_CODE (x)) == '1'
|| GET_RTX_CLASS (GET_CODE (x)) == '3')
return ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno);
switch (GET_CODE (x))
{
case REG:
return 1;
case MEM:
if ((GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
&& REGNO (XEXP (XEXP (x, 0), 0)) == regno)
|| (GET_CODE (XEXP (x, 0)) == REG
&& REGNO (XEXP (x, 0)) == regno))
return 0;
else
return 1;
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
case CC0:
case PC:
return 1;
default:
return 0;
}
}
#ifdef IP2K_MD_REORG_PASS
static void
mdr_try_propagate_move_sequence (first_insn, orig, equiv)
rtx first_insn;
rtx orig;
rtx equiv;
{
rtx try_insn;
for (try_insn = next_nonnote_insn (first_insn); try_insn;
try_insn = next_nonnote_insn (try_insn))
{
rtx set;
int range;
rtx new_equiv = NULL_RTX;
if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
break;
set = single_set (try_insn);
if (set == NULL_RTX)
break;
range = MAX (GET_MODE_SIZE (GET_MODE (equiv)),
GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
if (GET_CODE (equiv) == REG
&& REGNO (equiv) == REG_W
&& (recog_memoized (try_insn) < 0
|| get_attr_clobberw (try_insn) != CLOBBERW_NO)
&& (! (GET_CODE (XEXP (set, 0)) == REG
&& REGNO (XEXP (set, 0)) == REG_W
&& rtx_equal_p (XEXP (set, 1), orig))))
break;
else if (GET_CODE (XEXP (set, 0)) == REG
&& (REGNO (XEXP (set, 0)) == REG_SP
|| ! ip2k_xexp_not_uses_reg_p (equiv, REGNO (XEXP (set, 0)),
range)
|| ! ip2k_xexp_not_uses_reg_p (orig, REGNO (XEXP (set, 0)),
range))
&& ! rtx_equal_p (equiv, XEXP (set, 0))
&& ! rtx_equal_p (orig, XEXP (set, 0)))
break;
else if (GET_CODE (orig) == REG
&& (REGNO (orig) == REG_IPL
|| REGNO (orig) == REG_IPH
|| REGNO (orig) == REG_DPL
|| REGNO (orig) == REG_DPH)
&& (! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 0),
REGNO (orig))
|| ! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 1),
REGNO (orig))))
break;
else if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (equiv) == MEM)
{
if (! ip2k_xexp_not_uses_reg_p (equiv, REG_SP, 2))
{
if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2))
{
if (GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
&& GET_CODE (XEXP (equiv, 0)) == PLUS
&& REGNO (XEXP (XEXP (equiv, 0), 0)) == REG_SP)
{
int md_size = GET_MODE_SIZE (GET_MODE (XEXP (set, 0)));
int new_sp_offs = INTVAL (XEXP (XEXP (equiv, 0), 1))
+ md_size;
if (new_sp_offs > (128 - 2 * md_size))
break;
new_equiv
= gen_rtx_MEM (GET_MODE (equiv),
gen_rtx_PLUS (Pmode,
gen_rtx_REG (HImode ,
REG_SP),
GEN_INT (new_sp_offs)));
}
else if (! rtx_equal_p (equiv, XEXP (set, 0)))
{
int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
? INTVAL (XEXP (XEXP (equiv, 0), 1))
: 0;
int set_offs
= (GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
: 0);
if (abs (equiv_offs - set_offs) < range)
break;
}
}
}
if (! ip2k_xexp_not_uses_reg_p (equiv, REG_IP, 2))
break;
if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_DP, 2)
&& ! ip2k_xexp_not_uses_reg_p (equiv, REG_DP, 2)
&& ! rtx_equal_p (equiv, XEXP (set, 0)))
{
int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
? INTVAL (XEXP (XEXP (equiv, 0), 1))
: 0;
int set_offs = GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
: 0;
if (abs (equiv_offs - set_offs) < range)
break;
}
}
validate_replace_rtx_subexp (orig, equiv, try_insn, &XEXP (set, 1));
if (rtx_equal_p (equiv, XEXP (set, 0))
|| rtx_equal_p (orig, XEXP (set, 0)))
break;
if (new_equiv != NULL_RTX)
equiv = new_equiv;
}
}
static void
mdr_try_propagate_move (first_insn)
rtx first_insn;
{
rtx insn;
rtx set;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) != INSN)
continue;
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
if (GET_CODE (XEXP (set, 0)) == REG
&& (REGNO (XEXP (set, 0)) >= 0x80
|| REGNO (XEXP (set, 0)) == REG_DPL
|| REGNO (XEXP (set, 0)) == REG_DPH
|| REGNO (XEXP (set, 0)) == REG_IPL
|| REGNO (XEXP (set, 0)) == REG_IPH)
&& ((GET_CODE (XEXP (set, 1)) == REG
&& REGNO (XEXP (set, 1)) != REG_SP
&& ip2k_xexp_not_uses_reg_p (XEXP (set, 0),
REGNO (XEXP (set, 1)),
GET_MODE_SIZE (GET_MODE (XEXP (set,
0)))))
|| (GET_CODE (XEXP (set, 1)) == MEM
&& (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_IP, 2)
|| GET_MODE (XEXP (set, 1)) == QImode)
&& ((REGNO (XEXP (set, 0)) != REG_DPH
&& REGNO (XEXP (set, 0)) != REG_DPL)
|| ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2)))
|| (GET_CODE (XEXP (set, 1)) == CONST_INT
&& (GET_MODE (XEXP (set, 0)) != QImode
|| INTVAL (XEXP (set, 1)) != 0))
|| GET_CODE (XEXP (set, 1)) == CONST_DOUBLE
|| GET_CODE (XEXP (set, 1)) == CONST
|| GET_CODE (XEXP (set, 1)) == SYMBOL_REF))
{
mdr_try_propagate_move_sequence (insn, XEXP (set, 0), XEXP (set, 1));
}
}
}
static void
mdr_try_remove_redundant_insns (first_insn)
rtx first_insn;
{
rtx insn;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
rtx set;
enum machine_mode mode;
int md_size;
HOST_WIDE_INT pattern;
int i;
if (GET_CODE (insn) != INSN)
continue;
if (GET_CODE (PATTERN (insn)) == CONST_INT)
{
rtx remove_insn = insn;
insn = prev_nonnote_insn (insn);
delete_insn (remove_insn);
continue;
}
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
continue;
mode = GET_MODE (XEXP (set, 0));
md_size = GET_MODE_SIZE (mode);
if ((md_size < 1) || (md_size > 4))
continue;
pattern = 0;
for (i = 0; i < md_size; i++)
{
pattern <<= 8;
pattern |= 0xff;
}
if ((GET_CODE (XEXP (set, 1)) == AND
&& GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (set, 1), 1)) == pattern)
|| ((GET_CODE (XEXP (set, 1)) == IOR
|| GET_CODE (XEXP (set, 1)) == XOR)
&& GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (set, 1), 1)) == 0x00))
{
rtx remove_insn = insn;
if (! rtx_equal_p (XEXP (set, 0), XEXP (XEXP (set, 1), 0)))
{
emit_insn_before (gen_rtx_SET (mode,
XEXP (set, 0),
XEXP (XEXP (set, 1), 0)),
insn);
}
insn = prev_nonnote_insn(insn);
delete_insn (remove_insn);
}
else if (GET_CODE (XEXP (set, 1)) == AND
&& GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (set, 1), 1)) == 0)
{
rtx remove_insn = insn;
insn = emit_insn_before (gen_rtx_SET (mode,
XEXP (set, 0),
XEXP (XEXP (set, 1), 1)),
insn);
delete_insn (remove_insn);
}
}
}
struct we_jump_targets
{
int target;
int reach_count;
int touch_count;
rtx w_equiv;
};
struct we_jump_targets *ip2k_we_jump_targets;
static int
track_w_reload (insn, w_current, w_current_ok, modifying)
rtx insn;
rtx *w_current;
int w_current_ok;
int modifying;
{
rtx set;
if (GET_CODE (insn) != INSN)
{
*w_current = NULL_RTX;
return 1;
}
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if (set == NULL_RTX)
{
*w_current = NULL_RTX;
return 1;
}
if (GET_CODE (XEXP (set, 0)) == REG
&& REGNO (XEXP (set, 0)) == REG_W
&& GET_MODE (XEXP (set, 0)) == QImode)
{
if (*w_current != NULL_RTX
&& rtx_equal_p (XEXP (set, 1), *w_current))
{
if (modifying)
delete_insn (insn);
}
else
{
*w_current = XEXP (set, 1);
return 1;
}
}
else if (recog_memoized (insn) < 0
|| get_attr_clobberw (insn) != CLOBBERW_NO)
{
*w_current = NULL_RTX;
return 1;
}
else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
&& *w_current != NULL_RTX
&& !ip2k_xexp_not_uses_reg_p (*w_current, REG_SP, 2))
{
if (GET_CODE (XEXP (set, 0)) == MEM
&& GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
&& GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
&& REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
&& GET_CODE (*w_current) == MEM
&& GET_CODE (XEXP (*w_current, 0)) == PLUS)
{
rtx val = GEN_INT (INTVAL (XEXP (XEXP (*w_current, 0), 1))
+ GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
*w_current
= gen_rtx_MEM (HImode, gen_rtx_PLUS (Pmode,
gen_rtx_REG(HImode, REG_SP),
val));
return 1;
}
}
else if (GET_CODE (XEXP (set, 0)) == REG
&& *w_current != NULL_RTX
&& !ip2k_xexp_not_uses_reg_p (*w_current, REGNO (XEXP (set, 0)),
GET_MODE_SIZE (GET_MODE (XEXP (set
, 0)))))
{
*w_current = NULL_RTX;
}
return w_current_ok;
}
static void
mdr_try_wreg_elim (first_insn)
rtx first_insn;
{
rtx insn;
struct we_jump_targets *wjt;
rtx w_current;
int incomplete_scan;
int last_incomplete_scan;
ip2k_we_jump_targets
= (struct we_jump_targets *) xcalloc (get_max_uid (),
sizeof (struct we_jump_targets));
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
wjt->target = 1;
wjt->reach_count = LABEL_NUSES (insn);
wjt->touch_count = 0;
wjt->w_equiv = NULL_RTX;
if (! prev_nonnote_insn (insn)
|| (prev_nonnote_insn (insn)
&& GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
wjt->reach_count++;
}
}
incomplete_scan = -1;
do
{
int w_current_ok = 0;
last_incomplete_scan = incomplete_scan;
w_current = NULL_RTX;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
if (wjt->touch_count == wjt->reach_count)
{
w_current = wjt->w_equiv;
w_current_ok = 1;
continue;
}
if (w_current_ok
&& (! prev_nonnote_insn (insn)
|| (prev_nonnote_insn (insn)
&& GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
{
if (wjt->touch_count == 0)
wjt->w_equiv = w_current;
if (wjt->touch_count < wjt->reach_count)
{
wjt->touch_count++;
if (! rtx_equal_p (wjt->w_equiv, w_current))
{
wjt->w_equiv = NULL_RTX;
w_current = NULL_RTX;
w_current_ok = 1;
}
}
}
if (wjt->touch_count < wjt->reach_count)
{
w_current = NULL_RTX;
w_current_ok = 0;
}
continue;
}
if (GET_CODE (insn) == JUMP_INSN)
{
if (w_current_ok)
{
if (JUMP_LABEL (insn))
{
wjt
= &ip2k_we_jump_targets[INSN_UID (JUMP_LABEL (insn))];
if (wjt->touch_count == 0)
wjt->w_equiv = w_current;
if (wjt->touch_count < wjt->reach_count)
{
wjt->touch_count++;
if (! rtx_equal_p (wjt->w_equiv, w_current))
wjt->w_equiv = NULL_RTX;
}
}
}
continue;
}
w_current_ok = track_w_reload (insn, &w_current, w_current_ok, 0);
}
incomplete_scan = 0;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
{
wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
if (wjt->touch_count != wjt->reach_count)
{
incomplete_scan += (wjt->reach_count - wjt->touch_count);
wjt->w_equiv = NULL_RTX;
wjt->touch_count = 0;
}
}
}
}
while (incomplete_scan && incomplete_scan != last_incomplete_scan);
w_current = NULL_RTX;
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == JUMP_INSN)
continue;
if (GET_CODE (insn) == CODE_LABEL)
{
wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
w_current = wjt->w_equiv;
continue;
}
track_w_reload (insn, &w_current, 1, 1);
}
free (ip2k_we_jump_targets);
}
#endif
void
machine_dependent_reorg (first_insn)
rtx first_insn ATTRIBUTE_UNUSED;
{
#ifdef IP2K_MD_REORG_PASS
rtx insn, set;
#endif
CC_STATUS_INIT;
if (optimize == 0)
{
ip2k_reorg_completed = 1;
ip2k_reorg_split_dimode = 1;
ip2k_reorg_split_simode = 1;
ip2k_reorg_split_himode = 1;
ip2k_reorg_split_qimode = 1;
ip2k_reorg_merge_qimode = 1;
return;
}
#ifndef IP2K_MD_REORG_PASS
ip2k_reorg_completed = 1;
ip2k_reorg_split_dimode = 1;
ip2k_reorg_split_simode = 1;
ip2k_reorg_split_himode = 1;
ip2k_reorg_split_qimode = 1;
ip2k_reorg_merge_qimode = 1;
#else
ip2k_reorg_in_progress = 1;
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
{
rtx body;
if (GET_CODE (insn) == CODE_LABEL
|| GET_CODE (insn) == NOTE
|| GET_CODE (insn) == BARRIER)
continue;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
body = PATTERN (insn);
if (GET_CODE (body) == USE)
if (GET_CODE (XEXP (body, 0)) == REG)
{
int reg;
reg = REGNO (XEXP (body, 0));
if (find_regno_note (insn, REG_DEAD, reg))
{
delete_insn (insn);
}
}
}
reload_cse_regs (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
mdr_try_dp_reload_elim (first_insn);
ip2k_reorg_in_progress = 0;
ip2k_reorg_completed = 1;
split_all_insns (0);
reload_cse_regs (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
if (flag_peephole2)
peephole2_optimize (NULL);
mdr_resequence_xy_yx (first_insn);
mdr_propagate_reg_equivs (first_insn);
for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
{
if (GET_CODE (insn) == INSN)
{
set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
if ((set != NULL_RTX)
&& (GET_CODE (XEXP (set, 0)) == REG)
&& (GET_MODE (XEXP (set, 0)) == QImode)
&& (find_regno_note (insn, REG_UNUSED, REGNO (XEXP (set, 0)))))
delete_insn (insn);
}
}
mdr_try_move_dp_reload (first_insn);
mdr_try_move_pushes (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
mdr_try_propagate_move (first_insn);
mdr_resequence_xy_yx (first_insn);
ip2k_reorg_split_dimode = 1;
split_all_insns (0);
mdr_try_remove_redundant_insns (first_insn);
mdr_try_propagate_move (first_insn);
reload_cse_regs (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
if (flag_peephole2)
peephole2_optimize (NULL);
mdr_try_propagate_move (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
ip2k_reorg_split_simode = 1;
split_all_insns (0);
mdr_try_remove_redundant_insns (first_insn);
mdr_try_propagate_move (first_insn);
reload_cse_regs (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
if (flag_peephole2)
peephole2_optimize (NULL);
mdr_try_propagate_move (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
ip2k_reorg_split_himode = 1;
ip2k_reorg_merge_qimode = 1;
split_all_insns (0);
mdr_try_remove_redundant_insns (first_insn);
mdr_try_propagate_clr (first_insn);
mdr_try_propagate_move (first_insn);
mdr_try_dp_reload_elim (first_insn);
mdr_try_move_dp_reload (first_insn);
rebuild_jump_labels (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
if (flag_peephole2)
peephole2_optimize (NULL);
mdr_try_propagate_move (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
mdr_try_remove_redundant_insns (first_insn);
mdr_try_propagate_clr (first_insn);
mdr_try_propagate_move (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
ip2k_reorg_split_qimode = 1;
split_all_insns (0);
mdr_try_wreg_elim (first_insn);
mdr_try_propagate_move (first_insn);
find_basic_blocks (first_insn, max_reg_num (), 0);
life_analysis (first_insn, 0, PROP_FINAL);
#endif
}
int
find_one_set_bit_p (mask)
HOST_WIDE_INT mask;
{
int i;
unsigned HOST_WIDE_INT n = mask;
for (i = 0; i < 32; i++)
{
if (n & 0x80000000UL)
{
if (n & 0x7fffffffUL)
return -1;
else
return 31 - i;
}
n <<= 1;
}
return -1;
}
int
find_one_clear_bit_p (mask)
HOST_WIDE_INT mask;
{
int i;
unsigned HOST_WIDE_INT n = mask;
for (i = 0; i < 32; i++)
{
if ((n & 0x80000000UL) == 0UL)
{
if ((n & 0x7fffffffUL) != 0x7fffffffUL)
return -1;
else
return 31 - i;
}
n <<= 1;
n |= 1;
}
return -1;
}
void
ip2k_split_words (nmode, omode, operands)
enum machine_mode nmode;
enum machine_mode omode;
rtx *operands;
{
rtx dl, dh;
rtx sl, sh;
int move_high_first = 0;
int pushflag = 0;
switch (GET_CODE (operands[0]))
{
case SUBREG:
case REG:
if ((GET_CODE (operands[1]) == REG
|| GET_CODE (operands[1]) == SUBREG)
&& (true_regnum (operands[0]) <= true_regnum (operands[1])
|| (true_regnum (operands[1])
+ GET_MODE_SIZE (omode) - 1 < true_regnum (operands[0]))))
move_high_first = 1;
if (GET_CODE (operands[0]) == SUBREG)
{
dl = simplify_gen_subreg (nmode, operands[0], omode,
GET_MODE_SIZE (nmode));
dh = simplify_gen_subreg (nmode, operands[0], omode, 0);
}
else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
{
int r = REGNO (operands[0]);
dh = gen_rtx_REG (nmode, r);
dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
}
else
{
dh = gen_rtx_SUBREG (nmode, operands[0], 0);
dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
}
break;
case MEM:
switch (GET_CODE (XEXP (operands[0], 0)))
{
case POST_INC:
abort ();
case POST_DEC:
dl = dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
pushflag = 1;
break;
default:
dl = change_address (operands[0], nmode,
plus_constant (XEXP (operands[0], 0),
GET_MODE_SIZE (nmode)));
dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
}
break;
default:
abort ();
}
switch (GET_CODE (operands[1]))
{
case REG:
if (! IS_PSEUDO_P (operands[1]))
{
int r = REGNO (operands[1]);
sh = gen_rtx_REG (nmode, r);
sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
}
else
{
sh = gen_rtx_SUBREG (nmode, operands[1], 0);
sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
}
break;
case CONST_DOUBLE:
if (operands[1] == const0_rtx)
sh = sl = const0_rtx;
else
{
if (GET_MODE (operands[0]) != DImode)
{
REAL_VALUE_TYPE rv;
long value;
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (rv, value);
sh = gen_int_mode ((value >> 16) & 0xffff, nmode);
sl = gen_int_mode (value & 0xffff, nmode);
}
else
{
sh = gen_int_mode (CONST_DOUBLE_HIGH (operands[1]), nmode);
sl = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), nmode);
}
}
break;
case CONST_INT:
if (operands[1] == const0_rtx)
sh = sl = const0_rtx;
else
{
int val = INTVAL (operands[1]);
int vl, vh;
switch (nmode)
{
case QImode:
vh = (val >> 8) & 0xff;
vl = val & 0xff;
break;
case HImode:
vh = (val >> 16) & 0xffff;
vl = val & 0xffff;
break;
case SImode:
if (val < 0)
vh = -1;
else
vh = 0;
vl = val;
break;
default:
abort ();
}
sl = gen_int_mode (vl, nmode);
sh = gen_int_mode (vh, nmode);
}
break;
case SUBREG:
sl = simplify_gen_subreg (nmode, operands[1], omode,
GET_MODE_SIZE (nmode));
sh = simplify_gen_subreg (nmode, operands[1], omode, 0);
break;
case MEM:
switch (GET_CODE (XEXP (operands[1], 0)))
{
case POST_DEC:
case POST_INC:
abort ();
break;
default:
if (pushflag && ip2k_address_uses_reg_p (operands[1], REG_SP))
sl = sh = change_address (operands[1], nmode,
plus_constant (XEXP (operands[1], 0),
GET_MODE_SIZE (nmode)));
else
{
sl = change_address (operands[1], nmode,
plus_constant (XEXP (operands[1], 0),
GET_MODE_SIZE (nmode)));
sh = gen_rtx_MEM (nmode, XEXP (operands[1], 0));
}
}
break;
default:
abort ();
}
if (move_high_first)
{
operands[2] = dh;
operands[3] = sh;
operands[4] = dl;
operands[5] = sl;
}
else
{
operands[2] = dl;
operands[3] = sl;
operands[4] = dh;
operands[5] = sh;
}
return;
}
rtx
ip2k_get_low_half (x, mode)
rtx x;
enum machine_mode mode;
{
switch (GET_CODE (x))
{
case REG:
if (! IS_PSEUDO_P (x))
{
unsigned int r = REGNO (x);
return gen_rtx_REG (mode, r + HARD_REGNO_NREGS (r, mode));
}
else
{
return gen_rtx_SUBREG (mode, x, GET_MODE_SIZE (mode));
}
break;
case CONST_DOUBLE:
if (x == const0_rtx)
return const0_rtx;
else
{
if (mode != SImode)
{
REAL_VALUE_TYPE rv;
long value;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, value);
return gen_int_mode (value & 0xffff, mode);
}
else
return gen_int_mode (CONST_DOUBLE_LOW (x), mode);
}
break;
case CONST_INT:
if (x == const0_rtx)
return const0_rtx;
else
{
int val = INTVAL (x);
int vl, vh;
switch (mode)
{
case QImode:
vh = (val >> 8) & 0xff;
vl = val & 0xff;
break;
case HImode:
vh = (val >> 16) & 0xffff;
vl = val & 0xffff;
break;
case SImode:
if (val < 0)
vh = -1;
else
vh = 0;
vl = val;
break;
default:
abort ();
}
return gen_int_mode (vl, mode);
}
break;
case SUBREG:
return simplify_gen_subreg (mode, x, GET_MODE (x), GET_MODE_SIZE (mode));
case MEM:
switch (GET_CODE (XEXP (x, 0)))
{
case POST_DEC:
case POST_INC:
abort ();
break;
default:
return change_address (x, mode,
plus_constant (XEXP (x, 0),
GET_MODE_SIZE (mode)));
}
break;
default:
abort ();
}
return NULL_RTX;
}
rtx
ip2k_get_high_half (x, mode)
rtx x;
enum machine_mode mode;
{
switch (GET_CODE (x))
{
case REG:
if (! IS_PSEUDO_P (x))
{
unsigned int r = REGNO (x);
return gen_rtx_REG (mode, r);
}
else
{
return gen_rtx_SUBREG (mode, x, 0);
}
break;
case CONST_DOUBLE:
if (x == const0_rtx)
return const0_rtx;
else
{
if (mode != SImode)
{
REAL_VALUE_TYPE rv;
long value;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, value);
return gen_int_mode ((value >> 16) & 0xffff, mode);
}
else
return gen_int_mode (CONST_DOUBLE_HIGH (x), mode);
}
break;
case CONST_INT:
if (x == const0_rtx)
return const0_rtx;
else
{
int val = INTVAL (x);
int vl, vh;
switch (mode)
{
case QImode:
vh = (val >> 8) & 0xff;
vl = val & 0xff;
break;
case HImode:
vh = (val >> 16) & 0xffff;
vl = val & 0xffff;
break;
case SImode:
if (val < 0)
vh = -1;
else
vh = 0;
vl = val;
break;
default:
abort ();
}
return gen_int_mode (vh, mode);
}
break;
case SUBREG:
return simplify_gen_subreg (mode, x, GET_MODE (x), 0);
break;
case MEM:
switch (GET_CODE (XEXP (x, 0)))
{
case POST_DEC:
case POST_INC:
abort ();
break;
default:
return change_address (x, mode, plus_constant (XEXP (x, 0), 0));
}
break;
default:
abort ();
}
return NULL_RTX;
}
int
ip2k_address_uses_reg_p (x, r)
rtx x;
unsigned int r;
{
if (GET_CODE (x) != MEM)
return 0;
x = XEXP (x, 0);
while (1)
switch (GET_CODE (x))
{
case POST_DEC:
case POST_INC:
case PRE_DEC:
case PRE_INC:
x = XEXP (x, 0);
break;
case PLUS:
if (ip2k_address_uses_reg_p (XEXP (x, 1), r))
return 1;
x = XEXP (x, 0);
break;
case SUBREG:
x = SUBREG_REG (x);
break;
case REG:
return ((REGNO (x) == r) || (REGNO (x) == (r - 1))) ? 1 : 0;
case MEM:
x = XEXP (x, 0);
break;
default:
return 0;
};
}
int
ip2k_xexp_not_uses_reg_p (x, r, rsz)
rtx x;
unsigned int r;
int rsz;
{
switch (GET_CODE (x))
{
case REG:
{
int msz = GET_MODE_SIZE (GET_MODE (x));
return (((REGNO (x) + msz - 1) < r)
|| (REGNO (x) > (r + rsz - 1)));
}
case MEM:
return !ip2k_address_uses_reg_p (x, r);
case LABEL_REF:
case SYMBOL_REF:
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case CC0:
case PC:
return 1;
default:
return 0;
}
}
int
ip2k_composite_xexp_not_uses_reg_p (x, r, rsz)
rtx x;
unsigned int r;
int rsz;
{
if (GET_RTX_CLASS (GET_CODE (x)) == 'b')
return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz)
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 2), r, rsz));
if (GET_RTX_CLASS (GET_CODE (x)) == '2'
|| GET_RTX_CLASS (GET_CODE (x)) == 'c'
|| GET_RTX_CLASS (GET_CODE (x)) == '<')
return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
&& ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz));
if (GET_RTX_CLASS (GET_CODE (x)) == '1'
|| GET_RTX_CLASS (GET_CODE (x)) == '3')
return ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz);
return ip2k_xexp_not_uses_reg_p (x, r, rsz);
}
int
ip2k_composite_xexp_not_uses_cc0_p (x)
rtx x;
{
if (GET_RTX_CLASS (GET_CODE (x)) == 'b')
return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
&& ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1))
&& ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 2)));
if (GET_RTX_CLASS (GET_CODE (x)) == '2'
|| GET_RTX_CLASS (GET_CODE (x)) == 'c'
|| GET_RTX_CLASS (GET_CODE (x)) == '<')
return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
&& ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1)));
if (GET_RTX_CLASS (GET_CODE (x)) == '1'
|| GET_RTX_CLASS (GET_CODE (x)) == '3')
return ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0));
return GET_CODE (x) != CC0;
}
int
ip2k_split_dest_operand (x, mode)
rtx x;
enum machine_mode mode;
{
return nonimmediate_operand (x, mode) || push_operand (x, mode);
}
int
ip2k_nonptr_operand (x, mode)
rtx x;
enum machine_mode mode;
{
return register_operand (x, mode) && !ip2k_ptr_operand (x, mode);
}
int
ip2k_ptr_operand (x, mode)
rtx x;
enum machine_mode mode;
{
if (GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
return (REG_P (x)
&& (mode == HImode || mode == VOIDmode)
&& (REGNO (x) == REG_IP
|| REGNO (x) == REG_DP
|| REGNO (x) == REG_SP));
}
int
ip2k_sp_operand (x, mode)
rtx x;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return REG_P (x) && REGNO (x) == REG_SP;
}
int
ip2k_ip_operand (x, mode)
rtx x;
enum machine_mode mode;
{
if (GET_CODE (x) != MEM)
return 0;
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS && XEXP (x, 1) == const0_rtx)
x = XEXP (x, 0);
if (! REG_P (x))
return 0;
if (GET_MODE_SIZE (mode) > 1)
return 0;
return REGNO (x) == REG_IP;
}
int
ip2k_short_operand (x, mode)
rtx x;
enum machine_mode mode;
{
int r;
unsigned int offs = 0;
if (! memory_operand (x, mode))
return 0;
x = XEXP (x, 0);
switch (GET_CODE (x))
{
default:
return 0;
case PLUS:
if (! REG_P (XEXP (x, 0))
|| GET_CODE (XEXP (x, 1)) != CONST_INT)
return 0;
offs = INTVAL (XEXP (x, 1));
if (128 <= offs)
return 0;
x = XEXP (x, 0);
case REG:
if (IS_PSEUDO_P (x))
return 0;
r = REGNO (x);
if (r == REG_IP && offs == 0 && GET_MODE_SIZE (mode) <= 1)
return 1;
return (r == REG_SP || r == REG_DP);
}
}
int
ip2k_nonsp_reg_operand (x, mode)
rtx x;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
return (REG_P (x) && REGNO (x) != REG_SP);
}
int
ip2k_gen_operand (x, mode)
rtx x;
enum machine_mode mode;
{
return ip2k_short_operand (x, mode)
|| (GET_CODE (x) == SUBREG
&& REG_P (SUBREG_REG (x)))
|| (ip2k_nonsp_reg_operand (x, mode));
}
int
ip2k_extra_constraint (x, c)
rtx x;
int c;
{
switch (c)
{
case 'S':
return ip2k_short_operand (x, GET_MODE (x));
case 'R':
return ip2k_ip_operand (x, GET_MODE (x));
case 'T':
return CONSTANT_P (x) && is_regfile_address (x);
default:
return 0;
}
}
int
ip2k_unary_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& GET_RTX_CLASS (GET_CODE (op)) == '1');
}
int
ip2k_binary_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& (GET_RTX_CLASS (GET_CODE (op)) == 'c'
|| GET_RTX_CLASS (GET_CODE (op)) == '2'));
}
int
ip2k_symbol_ref_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == SYMBOL_REF)
|| (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF);
}
int
ip2k_signed_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return (comparison_operator (op, mode)
&& signed_condition (GET_CODE (op)) == GET_CODE (op));
}
int
ip2k_unsigned_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
return (comparison_operator (op, mode)
&& unsigned_condition (GET_CODE (op)) == GET_CODE (op));
}