bfin-protos.h (bfin_hardware_loop): Declare.

* config/bfin/bfin-protos.h (bfin_hardware_loop): Declare.
	* config/bfin/bfin.c (basic-block.h): Include.
	(struct machine_function): New.
	(bfin_init_machine_status): New.
	(override_options): Initialize init_machine_status.
	(bfin_hardware_loop): New.
	(MAX_LOOP_DEPTH, MAX_LOOP_LENGTH): Define.
	(DEF_VEC_P (loop_info)): New.
	(DEF_VEC_ALLOC_P (loop_info,heap)): New.
	(struct loop_info): New.
	(loop_info): New typedef.
	(struct loop_work): New.
	(loop_work): New typedef.
	(DEF_VEC_O (loop_work)): New.
	(DEF_VEC_ALLOC_O (loop_work,heap)): New.
	(bfin_dump_loops): New.
	(bfin_bb_in_loop): New.
	(bfin_scan_loop): New.
	(bfin_optimize_loop): New.
	(bfin_reorg_loops): New.
	(bfin_reorg): Use bfin_reorg_loops.
	* config/bfin/bfin.h (FIRST_PSEUDO_REGISTER): Adjust for adding
	loop registers.
	(I_REGNO_P): Simplify.
	(DP_REGNO_P, DPREG_P): New macros.
	(REGISTER_NAMES, FIXED_REGISTERS, CALL_USED_REGISTERS,
	REG_ALLOC_ORDER): Add LT0, LT1, LC0, LC1, LB0, LB1.
	(enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS):
	Add LT_REGS, LC_REGS, LB_REGS.
	(REG_CLASS_FROM_LETTER): Add 't' for LT_REGS, 'k' for LC_REGS,
	'l' for LB_REGS.
	(REGNO_REG_CLASS): Deal with loop registers.
	* config/bfin/bfin.md: Add comment for 't', 'k', 'l' constraint
	letters.
	(REG_LT0, REG_LT1, REG_LC0, REG_LC1, REG_LB0, REG_LB1):
	New constants for loop registers.
	(UNSPEC_LSETUP_END): New.
	(seq_insns): New define_attr. Set it for appropriate insns.
	(movsi_insn): Add alternatives for move from/to
	loop count registers.
	(doloop_end): New define_expand.
	(loop_end): New define_insn.
	(define_split for bad doloop_end): New.
	(lsetup_with_autoinit): New define_insn.
	(lsetup_without_autoinit): New define_insn.
	(rep_movsi, rep_movhi): Clobber LT1, LC1, LB1.
	* config/bfin/predicates.md (lc_register_operand): New.
	(lt_register_operand): New.
	(lb_register_operand): New.
	(nondp_register_operand): New.
	(nondp_reg_or_memory_operand): New.
        * doc/md.texi: Document Blackfin new 't', 'k', 'l' constraint letters.

From-SVN: r114274
This commit is contained in:
Jie Zhang 2006-05-31 16:46:15 +00:00 committed by Jie Zhang
parent 5dd59f65ca
commit b03149e136
6 changed files with 1074 additions and 46 deletions

View File

@ -1,3 +1,58 @@
2006-05-31 Jie Zhang <jie.zhang@analog.com>
* config/bfin/bfin-protos.h (bfin_hardware_loop): Declare.
* config/bfin/bfin.c (basic-block.h): Include.
(struct machine_function): New.
(bfin_init_machine_status): New.
(override_options): Initialize init_machine_status.
(bfin_hardware_loop): New.
(MAX_LOOP_DEPTH, MAX_LOOP_LENGTH): Define.
(DEF_VEC_P (loop_info)): New.
(DEF_VEC_ALLOC_P (loop_info,heap)): New.
(struct loop_info): New.
(loop_info): New typedef.
(struct loop_work): New.
(loop_work): New typedef.
(DEF_VEC_O (loop_work)): New.
(DEF_VEC_ALLOC_O (loop_work,heap)): New.
(bfin_dump_loops): New.
(bfin_bb_in_loop): New.
(bfin_scan_loop): New.
(bfin_optimize_loop): New.
(bfin_reorg_loops): New.
(bfin_reorg): Use bfin_reorg_loops.
* config/bfin/bfin.h (FIRST_PSEUDO_REGISTER): Adjust for adding
loop registers.
(I_REGNO_P): Simplify.
(DP_REGNO_P, DPREG_P): New macros.
(REGISTER_NAMES, FIXED_REGISTERS, CALL_USED_REGISTERS,
REG_ALLOC_ORDER): Add LT0, LT1, LC0, LC1, LB0, LB1.
(enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS):
Add LT_REGS, LC_REGS, LB_REGS.
(REG_CLASS_FROM_LETTER): Add 't' for LT_REGS, 'k' for LC_REGS,
'l' for LB_REGS.
(REGNO_REG_CLASS): Deal with loop registers.
* config/bfin/bfin.md: Add comment for 't', 'k', 'l' constraint
letters.
(REG_LT0, REG_LT1, REG_LC0, REG_LC1, REG_LB0, REG_LB1):
New constants for loop registers.
(UNSPEC_LSETUP_END): New.
(seq_insns): New define_attr. Set it for appropriate insns.
(movsi_insn): Add alternatives for move from/to
loop count registers.
(doloop_end): New define_expand.
(loop_end): New define_insn.
(define_split for bad doloop_end): New.
(lsetup_with_autoinit): New define_insn.
(lsetup_without_autoinit): New define_insn.
(rep_movsi, rep_movhi): Clobber LT1, LC1, LB1.
* config/bfin/predicates.md (lc_register_operand): New.
(lt_register_operand): New.
(lb_register_operand): New.
(nondp_register_operand): New.
(nondp_reg_or_memory_operand): New.
* doc/md.texi: Document Blackfin new 't', 'k', 'l' constraint letters.
2006-05-31 Jie Zhang <jie.zhang@analog.com>
* config/bfin/bfin.c (bfin_delegitimize_address): New.

View File

@ -83,6 +83,7 @@ extern void output_push_multiple (rtx, rtx *);
extern void output_pop_multiple (rtx, rtx *);
extern int bfin_hard_regno_rename_ok (unsigned int, unsigned int);
extern rtx bfin_return_addr_rtx (int);
extern void bfin_hardware_loop (void);
#undef Mmode
#endif

View File

@ -51,6 +51,14 @@
#include "bfin-protos.h"
#include "tm-preds.h"
#include "gt-bfin.h"
#include "basic-block.h"
/* A C structure for machine-specific, per-function data.
This is added to the cfun structure. */
struct machine_function GTY(())
{
int has_hardware_loops;
};
/* Test and compare insns in bfin.md store the information needed to
generate branch and scc insns here. */
@ -1957,6 +1965,16 @@ bfin_handle_option (size_t code, const char *arg, int value)
}
}
static struct machine_function *
bfin_init_machine_status (void)
{
struct machine_function *f;
f = ggc_alloc_cleared (sizeof (struct machine_function));
return f;
}
/* Implement the macro OVERRIDE_OPTIONS. */
void
@ -1987,6 +2005,8 @@ override_options (void)
flag_pic = 0;
flag_schedule_insns = 0;
init_machine_status = bfin_init_machine_status;
}
/* Return the destination address of BRANCH.
@ -2704,6 +2724,771 @@ bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
return cost;
}
/* Increment the counter for the number of loop instructions in the
current function. */
void
bfin_hardware_loop (void)
{
cfun->machine->has_hardware_loops++;
}
/* Maxium loop nesting depth. */
#define MAX_LOOP_DEPTH 2
/* Maxium size of a loop. */
#define MAX_LOOP_LENGTH 4096
/* We need to keep a vector of loops */
typedef struct loop_info *loop_info;
DEF_VEC_P (loop_info);
DEF_VEC_ALLOC_P (loop_info,heap);
/* Information about a loop we have found (or are in the process of
finding). */
struct loop_info GTY (())
{
/* loop number, for dumps */
int loop_no;
/* Predecessor block of the loop. This is the one that falls into
the loop and contains the initialization instruction. */
basic_block predecessor;
/* First block in the loop. This is the one branched to by the loop_end
insn. */
basic_block head;
/* Last block in the loop (the one with the loop_end insn). */
basic_block tail;
/* The successor block of the loop. This is the one the loop_end insn
falls into. */
basic_block successor;
/* The last instruction in the tail. */
rtx last_insn;
/* The loop_end insn. */
rtx loop_end;
/* The iteration register. */
rtx iter_reg;
/* The new initialization insn. */
rtx init;
/* The new initialization instruction. */
rtx loop_init;
/* The new label placed at the beginning of the loop. */
rtx start_label;
/* The new label placed at the end of the loop. */
rtx end_label;
/* The length of the loop. */
int length;
/* The nesting depth of the loop. Set to -1 for a bad loop. */
int depth;
/* True if we have visited this loop. */
int visited;
/* True if this loop body clobbers any of LC0, LT0, or LB0. */
int clobber_loop0;
/* True if this loop body clobbers any of LC1, LT1, or LB1. */
int clobber_loop1;
/* Next loop in the graph. */
struct loop_info *next;
/* Immediate outer loop of this loop. */
struct loop_info *outer;
/* Vector of blocks only within the loop, (excluding those within
inner loops). */
VEC (basic_block,heap) *blocks;
/* Vector of inner loops within this loop */
VEC (loop_info,heap) *loops;
};
/* Information used during loop detection. */
typedef struct loop_work GTY(())
{
/* Basic block to be scanned. */
basic_block block;
/* Loop it will be within. */
loop_info loop;
} loop_work;
/* Work list. */
DEF_VEC_O (loop_work);
DEF_VEC_ALLOC_O (loop_work,heap);
static void
bfin_dump_loops (loop_info loops)
{
loop_info loop;
for (loop = loops; loop; loop = loop->next)
{
loop_info i;
basic_block b;
unsigned ix;
fprintf (dump_file, ";; loop %d: ", loop->loop_no);
fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
fprintf (dump_file, " blocks: [ ");
for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
fprintf (dump_file, "%d ", b->index);
fprintf (dump_file, "] ");
fprintf (dump_file, " inner loops: [ ");
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
fprintf (dump_file, "%d ", i->loop_no);
fprintf (dump_file, "]\n");
}
fprintf (dump_file, "\n");
}
/* Scan the blocks of LOOP (and its inferiors) looking for basic block
BB. Return true, if we find it. */
static bool
bfin_bb_in_loop (loop_info loop, basic_block bb)
{
unsigned ix;
loop_info inner;
basic_block b;
for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
if (b == bb)
return true;
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
if (bfin_bb_in_loop (inner, bb))
return true;
return false;
}
/* Scan the blocks of LOOP (and its inferiors) looking for uses of
REG. Return true, if we find any. Don't count the loop's loop_end
insn if it matches LOOP_END. */
static bool
bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
{
unsigned ix;
loop_info inner;
basic_block bb;
for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
{
rtx insn;
for (insn = BB_HEAD (bb);
insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
{
if (!INSN_P (insn))
continue;
if (insn == loop_end)
continue;
if (reg_mentioned_p (reg, PATTERN (insn)))
return true;
}
}
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
if (bfin_scan_loop (inner, reg, NULL_RTX))
return true;
return false;
}
/* Optimize LOOP. */
static void
bfin_optimize_loop (loop_info loop)
{
basic_block bb;
loop_info inner, outer;
rtx insn, init_insn, last_insn, nop_insn;
rtx loop_init, start_label, end_label;
rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
rtx iter_reg;
rtx lc_reg, lt_reg, lb_reg;
rtx seq;
int length;
unsigned ix;
int inner_depth = 0;
int inner_num;
int bb_num;
if (loop->visited)
return;
loop->visited = 1;
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
{
if (inner->loop_no == loop->loop_no)
loop->depth = -1;
else
bfin_optimize_loop (inner);
if (inner->depth < 0 || inner->depth > MAX_LOOP_DEPTH)
{
inner->outer = NULL;
VEC_ordered_remove (loop_info, loop->loops, ix);
}
if (inner_depth < inner->depth)
inner_depth = inner->depth;
loop->clobber_loop0 |= inner->clobber_loop0;
loop->clobber_loop1 |= inner->clobber_loop1;
}
if (loop->depth < 0)
{
if (dump_file)
fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
goto bad_loop;
}
loop->depth = inner_depth + 1;
if (loop->depth > MAX_LOOP_DEPTH)
{
if (dump_file)
fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
goto bad_loop;
}
/* Make sure we only have one entry point. */
if (EDGE_COUNT (loop->head->preds) == 2)
{
loop->predecessor = EDGE_PRED (loop->head, 0)->src;
if (loop->predecessor == loop->tail)
/* We wanted the other predecessor. */
loop->predecessor = EDGE_PRED (loop->head, 1)->src;
/* We can only place a loop insn on a fall through edge of a
single exit block. */
if (EDGE_COUNT (loop->predecessor->succs) != 1
|| !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU)
/* If loop->predecessor is in loop, loop->head is not really
the head of the loop. */
|| bfin_bb_in_loop (loop, loop->predecessor))
loop->predecessor = NULL;
}
if (loop->predecessor == NULL)
{
if (dump_file)
fprintf (dump_file, ";; loop %d has bad predecessor\n", loop->loop_no);
goto bad_loop;
}
/* Get the loop iteration register. */
iter_reg = loop->iter_reg;
if (!DPREG_P (iter_reg))
{
if (dump_file)
fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n",
loop->loop_no);
goto bad_loop;
}
/* Check if start_label appears before loop_end and calculate the
offset between them. We calculate the length of instructions
conservatively. */
length = 0;
for (insn = loop->start_label;
insn && insn != loop->loop_end;
insn = NEXT_INSN (insn))
{
if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
{
if (TARGET_CSYNC_ANOMALY)
length += 8;
else if (TARGET_SPECLD_ANOMALY)
length += 6;
}
else if (LABEL_P (insn))
{
if (TARGET_CSYNC_ANOMALY)
length += 4;
}
if (INSN_P (insn))
length += get_attr_length (insn);
}
if (!insn)
{
if (dump_file)
fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
loop->loop_no);
goto bad_loop;
}
loop->length = length;
if (loop->length > MAX_LOOP_LENGTH)
{
if (dump_file)
fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
goto bad_loop;
}
/* Scan all the blocks to make sure they don't use iter_reg. */
if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
{
if (dump_file)
fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
goto bad_loop;
}
/* Scan all the insns to see if the loop body clobber
any hardware loop registers. */
reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
{
rtx insn;
for (insn = BB_HEAD (bb);
insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
{
if (!INSN_P (insn))
continue;
if (reg_set_p (reg_lc0, insn)
|| reg_set_p (reg_lt0, insn)
|| reg_set_p (reg_lb0, insn))
loop->clobber_loop0 = 1;
if (reg_set_p (reg_lc1, insn)
|| reg_set_p (reg_lt1, insn)
|| reg_set_p (reg_lb1, insn))
loop->clobber_loop1 |= 1;
}
}
if ((loop->clobber_loop0 && loop->clobber_loop1)
|| (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
{
loop->depth = MAX_LOOP_DEPTH + 1;
if (dump_file)
fprintf (dump_file, ";; loop %d no loop reg available\n",
loop->loop_no);
goto bad_loop;
}
/* There should be an instruction before the loop_end instruction
in the same basic block. And the instruction must not be
- JUMP
- CONDITIONAL BRANCH
- CALL
- CSYNC
- SSYNC
- Returns (RTS, RTN, etc.) */
bb = loop->tail;
last_insn = PREV_INSN (loop->loop_end);
while (1)
{
for (; last_insn != PREV_INSN (BB_HEAD (bb));
last_insn = PREV_INSN (last_insn))
if (INSN_P (last_insn))
break;
if (last_insn != PREV_INSN (BB_HEAD (bb)))
break;
if (single_pred_p (bb)
&& single_pred (bb) != ENTRY_BLOCK_PTR)
{
bb = single_pred (bb);
last_insn = BB_END (bb);
continue;
}
else
{
last_insn = NULL_RTX;
break;
}
}
if (!last_insn)
{
if (dump_file)
fprintf (dump_file, ";; loop %d has no last instruction\n",
loop->loop_no);
goto bad_loop;
}
if (JUMP_P (last_insn))
{
loop_info inner = bb->aux;
if (inner
&& inner->outer == loop
&& inner->loop_end == last_insn
&& inner->depth == 1)
/* This jump_insn is the exact loop_end of an inner loop
and to be optimized away. So use the inner's last_insn. */
last_insn = inner->last_insn;
else
{
if (dump_file)
fprintf (dump_file, ";; loop %d has bad last instruction\n",
loop->loop_no);
goto bad_loop;
}
}
else if (CALL_P (last_insn)
|| get_attr_type (last_insn) == TYPE_SYNC
|| recog_memoized (last_insn) == CODE_FOR_return_internal)
{
if (dump_file)
fprintf (dump_file, ";; loop %d has bad last instruction\n",
loop->loop_no);
goto bad_loop;
}
if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
|| asm_noperands (PATTERN (last_insn)) >= 0
|| get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI)
{
nop_insn = emit_insn_after (gen_nop (), last_insn);
last_insn = nop_insn;
}
loop->last_insn = last_insn;
/* The loop is good for replacement. */
start_label = loop->start_label;
end_label = gen_label_rtx ();
iter_reg = loop->iter_reg;
if (loop->depth == 1 && !loop->clobber_loop1)
{
lc_reg = reg_lc1;
lt_reg = reg_lt1;
lb_reg = reg_lb1;
loop->clobber_loop1 = 1;
}
else
{
lc_reg = reg_lc0;
lt_reg = reg_lt0;
lb_reg = reg_lb0;
loop->clobber_loop0 = 1;
}
/* If iter_reg is a DREG, we need generate an instruction to load
the loop count into LC register. */
if (D_REGNO_P (REGNO (iter_reg)))
{
init_insn = gen_movsi (lc_reg, iter_reg);
loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
lb_reg, end_label,
lc_reg);
}
else if (P_REGNO_P (REGNO (iter_reg)))
{
init_insn = NULL_RTX;
loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
lb_reg, end_label,
lc_reg, iter_reg);
}
else
gcc_unreachable ();
loop->init = init_insn;
loop->end_label = end_label;
loop->loop_init = loop_init;
if (dump_file)
{
fprintf (dump_file, ";; replacing loop %d initializer with\n",
loop->loop_no);
print_rtl_single (dump_file, loop->loop_init);
fprintf (dump_file, ";; replacing loop %d terminator with\n",
loop->loop_no);
print_rtl_single (dump_file, loop->loop_end);
}
start_sequence ();
if (loop->init != NULL_RTX)
emit_insn (loop->init);
emit_insn(loop->loop_init);
emit_label (loop->start_label);
seq = get_insns ();
end_sequence ();
emit_insn_after (seq, BB_END (loop->predecessor));
delete_insn (loop->loop_end);
/* Insert the loop end label before the last instruction of the loop. */
emit_label_before (loop->end_label, loop->last_insn);
return;
bad_loop:
if (dump_file)
fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
/* Mark this loop bad. */
if (loop->depth <= MAX_LOOP_DEPTH)
loop->depth = -1;
outer = loop->outer;
/* Move all inner loops to loop's outer loop. */
inner_num = VEC_length (loop_info, loop->loops);
if (inner_num)
{
loop_info l;
if (outer)
VEC_reserve (loop_info, heap, outer->loops, inner_num);
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, l); ix++)
{
l->outer = outer;
if (outer)
VEC_quick_push (loop_info, outer->loops, l);
}
VEC_free (loop_info, heap, loop->loops);
}
/* Move all blocks to loop's outer loop. */
bb_num = VEC_length (basic_block, loop->blocks);
if (bb_num)
{
basic_block b;
if (outer)
VEC_reserve (basic_block, heap, outer->blocks, bb_num);
for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
{
b->aux = outer;
if (outer)
VEC_quick_push (basic_block, outer->blocks, b);
}
VEC_free (basic_block, heap, loop->blocks);
}
if (DPREG_P (loop->iter_reg))
{
/* If loop->iter_reg is a DREG or PREG, we can split it here
without scratch register. */
rtx insn;
emit_insn_before (gen_addsi3 (loop->iter_reg,
loop->iter_reg,
constm1_rtx),
loop->loop_end);
emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
loop->loop_end);
insn = emit_jump_insn_before (gen_bne (loop->start_label),
loop->loop_end);
JUMP_LABEL (insn) = loop->start_label;
LABEL_NUSES (loop->start_label)++;
delete_insn (loop->loop_end);
}
}
static void
bfin_reorg_loops (FILE *dump_file)
{
basic_block bb;
loop_info loops = NULL;
loop_info loop;
int nloops = 0;
unsigned dwork = 0;
VEC (loop_work,heap) *works = VEC_alloc (loop_work,heap,20);
loop_work *work;
edge e;
edge_iterator ei;
/* Find all the possible loop tails. This means searching for every
loop_end instruction. For each one found, create a loop_info
structure and add the head block to the work list. */
FOR_EACH_BB (bb)
{
rtx tail = BB_END (bb);
while (GET_CODE (tail) == NOTE)
tail = PREV_INSN (tail);
bb->aux = NULL;
if (recog_memoized (tail) == CODE_FOR_loop_end)
{
/* A possible loop end */
loop = XNEW (struct loop_info);
loop->next = loops;
loops = loop;
loop->tail = bb;
loop->head = BRANCH_EDGE (bb)->dest;
loop->successor = FALLTHRU_EDGE (bb)->dest;
loop->predecessor = NULL;
loop->loop_end = tail;
loop->last_insn = NULL_RTX;
loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail), 0, 1));
loop->depth = loop->length = 0;
loop->visited = 0;
loop->clobber_loop0 = loop->clobber_loop1 = 0;
loop->blocks = VEC_alloc (basic_block, heap, 20);
VEC_quick_push (basic_block, loop->blocks, bb);
loop->outer = NULL;
loop->loops = NULL;
loop->loop_no = nloops++;
loop->init = loop->loop_init = NULL_RTX;
loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail), 0, 0)), 1), 0);
loop->end_label = NULL_RTX;
work = VEC_safe_push (loop_work, heap, works, NULL);
work->block = loop->head;
work->loop = loop;
bb->aux = loop;
if (dump_file)
{
fprintf (dump_file, ";; potential loop %d ending at\n",
loop->loop_no);
print_rtl_single (dump_file, tail);
}
}
}
/* Now find all the closed loops.
until work list empty,
if block's auxptr is set
if != loop slot
if block's loop's start != block
mark loop as bad
else
append block's loop's fallthrough block to worklist
increment this loop's depth
else if block is exit block
mark loop as bad
else
set auxptr
for each target of block
add to worklist */
while (VEC_iterate (loop_work, works, dwork++, work))
{
loop = work->loop;
bb = work->block;
if (bb == EXIT_BLOCK_PTR)
/* We've reached the exit block. The loop must be bad. */
loop->depth = -1;
else if (!bb->aux)
{
/* We've not seen this block before. Add it to the loop's
list and then add each successor to the work list. */
bb->aux = loop;
VEC_safe_push (basic_block, heap, loop->blocks, bb);
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (!VEC_space (loop_work, works, 1))
{
if (dwork)
{
VEC_block_remove (loop_work, works, 0, dwork);
dwork = 0;
}
else
VEC_reserve (loop_work, heap, works, 1);
}
work = VEC_quick_push (loop_work, works, NULL);
work->block = EDGE_SUCC (bb, ei.index)->dest;
work->loop = loop;
}
}
else if (bb->aux != loop)
{
/* We've seen this block in a different loop. If it's not
the other loop's head, then this loop must be bad.
Otherwise, the other loop might be a nested loop, so
continue from that loop's successor. */
loop_info other = bb->aux;
if (other->head != bb)
loop->depth = -1;
else
{
other->outer = loop;
VEC_safe_push (loop_info, heap, loop->loops, other);
work = VEC_safe_push (loop_work, heap, works, NULL);
work->loop = loop;
work->block = other->successor;
}
}
}
VEC_free (loop_work, heap, works);
if (dump_file)
{
fprintf (dump_file, ";; All loops found:\n\n");
bfin_dump_loops (loops);
}
/* Now apply the optimizations. */
for (loop = loops; loop; loop = loop->next)
bfin_optimize_loop (loop);
if (dump_file)
{
fprintf (dump_file, ";; After hardware loops optimization:\n\n");
bfin_dump_loops (loops);
}
/* Free up the loop structures */
while (loops)
{
loop = loops;
loops = loop->next;
VEC_free (loop_info, heap, loop->loops);
VEC_free (basic_block, heap, loop->blocks);
XDELETE (loop);
}
if (dump_file)
print_rtl (dump_file, get_insns ());
}
/* We use the machine specific reorg pass for emitting CSYNC instructions
after conditional branches as needed.
@ -2731,7 +3516,11 @@ bfin_reorg (void)
rtx insn, last_condjump = NULL_RTX;
int cycles_since_jump = INT_MAX;
if (! TARGET_SPECLD_ANOMALY || ! TARGET_CSYNC_ANOMALY)
/* Doloop optimization */
if (cfun->machine->has_hardware_loops)
bfin_reorg_loops (dump_file);
if (! TARGET_SPECLD_ANOMALY && ! TARGET_CSYNC_ANOMALY)
return;
/* First pass: find predicted-false branches; if something after them

View File

@ -268,15 +268,17 @@ extern const char *bfin_library_id_string;
5 return address registers RETS/I/X/N/E
1 arithmetic status register (ASTAT). */
#define FIRST_PSEUDO_REGISTER 44
#define FIRST_PSEUDO_REGISTER 50
#define PREG_P(X) (REG_P (X) && P_REGNO_P (REGNO (X)))
#define IREG_P(X) (REG_P (X) && I_REGNO_P (REGNO (X)))
#define ADDRESS_REGNO_P(X) ((X) >= REG_P0 && (X) <= REG_M3)
#define D_REGNO_P(X) ((X) <= REG_R7)
#define P_REGNO_P(X) ((X) >= REG_P0 && (X) <= REG_P7)
#define I_REGNO_P(X) \
((X) == REG_I0 || (X) == REG_I1 || (X) == REG_I2 || (X) == REG_I3)
#define I_REGNO_P(X) ((X) >= REG_I0 && (X) <= REG_I3)
#define DP_REGNO_P(X) (D_REGNO_P (X) || P_REGNO_P (X))
#define ADDRESS_REGNO_P(X) ((X) >= REG_P0 && (X) <= REG_M3)
#define DREG_P(X) (REG_P (X) && D_REGNO_P (REGNO (X)))
#define PREG_P(X) (REG_P (X) && P_REGNO_P (REGNO (X)))
#define IREG_P(X) (REG_P (X) && I_REGNO_P (REGNO (X)))
#define DPREG_P(X) (REG_P (X) && DP_REGNO_P (REGNO (X)))
#define REGISTER_NAMES { \
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \
@ -286,7 +288,8 @@ extern const char *bfin_library_id_string;
"A0", "A1", \
"CC", \
"RETS", "RETI", "RETX", "RETN", "RETE", "ASTAT", "SEQSTAT", "USP", \
"ARGP" \
"ARGP", \
"LT0", "LT1", "LC0", "LC1", "LB0", "LB1" \
}
#define SHORT_REGISTER_NAMES { \
@ -316,8 +319,10 @@ extern const char *bfin_library_id_string;
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, \
/*i0 i1 i2 i3 b0 b1 b2 b3 l0 l1 l2 l3 m0 m1 m2 m3 */ \
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, \
/*a0 a1 cc rets/i/x/n/e astat seqstat usp argp */ \
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 \
/*a0 a1 cc rets/i/x/n/e astat seqstat usp argp lt0/1 lc0/1 */ \
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
/*lb0/1 */ \
1, 1 \
}
/* 1 for registers not available across function calls.
@ -332,8 +337,10 @@ extern const char *bfin_library_id_string;
{ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, \
/*i0 i1 i2 i3 b0 b1 b2 b3 l0 l1 l2 l3 m0 m1 m2 m3 */ \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
/*a0 a1 cc rets/i/x/n/e astat seqstat usp argp */ \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \
/*a0 a1 cc rets/i/x/n/e astat seqstat usp argp lt0/1 lc0/1 */ \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
/*lb0/1 */ \
1, 1 \
}
/* Order in which to allocate registers. Each register must be
@ -350,7 +357,8 @@ extern const char *bfin_library_id_string;
REG_L0, REG_L1, REG_L2, REG_L3, REG_M0, REG_M1, REG_M2, REG_M3, \
REG_RETS, REG_RETI, REG_RETX, REG_RETN, REG_RETE, \
REG_ASTAT, REG_SEQSTAT, REG_USP, \
REG_CC, REG_ARGP \
REG_CC, REG_ARGP, \
REG_LT0, REG_LT1, REG_LC0, REG_LC1, REG_LB0, REG_LB1 \
}
/* Macro to conditionally modify fixed_regs/call_used_regs. */
@ -410,6 +418,9 @@ enum reg_class
IPREGS,
DPREGS,
MOST_REGS,
LT_REGS,
LC_REGS,
LB_REGS,
PROLOGUE_REGS,
NON_A_CC_REGS,
ALL_REGS, LIM_REG_CLASSES
@ -443,6 +454,9 @@ enum reg_class
"IPREGS", \
"DPREGS", \
"MOST_REGS", \
"LT_REGS", \
"LC_REGS", \
"LB_REGS", \
"PROLOGUE_REGS", \
"NON_A_CC_REGS", \
"ALL_REGS" }
@ -484,9 +498,12 @@ enum reg_class
{ 0x000fff00, 0x800 }, /* IPREGS */ \
{ 0x0000ffff, 0x800 }, /* DPREGS */ \
{ 0xffffffff, 0x800 }, /* MOST_REGS */\
{ 0x00000000, 0x7f8 }, /* PROLOGUE_REGS */\
{ 0xffffffff, 0xff8 }, /* NON_A_CC_REGS */\
{ 0xffffffff, 0xfff }} /* ALL_REGS */
{ 0x00000000, 0x3000 }, /* LT_REGS */\
{ 0x00000000, 0xc000 }, /* LC_REGS */\
{ 0x00000000, 0x30000 }, /* LB_REGS */\
{ 0x00000000, 0x3f7f8 }, /* PROLOGUE_REGS */\
{ 0xffffffff, 0x3fff8 }, /* NON_A_CC_REGS */\
{ 0xffffffff, 0x3ffff }} /* ALL_REGS */
#define IREG_POSSIBLE_P(OUTER) \
((OUTER) == POST_INC || (OUTER) == PRE_INC \
@ -535,6 +552,9 @@ enum reg_class
(LETTER) == 'f' ? MREGS : \
(LETTER) == 'c' ? CIRCREGS : \
(LETTER) == 'C' ? CCREGS : \
(LETTER) == 't' ? LT_REGS : \
(LETTER) == 'k' ? LC_REGS : \
(LETTER) == 'l' ? LB_REGS : \
(LETTER) == 'x' ? MOST_REGS : \
(LETTER) == 'y' ? PROLOGUE_REGS : \
(LETTER) == 'w' ? NON_A_CC_REGS : \
@ -554,6 +574,9 @@ enum reg_class
: (REGNO) >= REG_B0 && (REGNO) <= REG_B3 ? BREGS \
: (REGNO) >= REG_M0 && (REGNO) <= REG_M3 ? MREGS \
: (REGNO) == REG_A0 || (REGNO) == REG_A1 ? AREGS \
: (REGNO) == REG_LT0 || (REGNO) == REG_LT1 ? LT_REGS \
: (REGNO) == REG_LC0 || (REGNO) == REG_LC1 ? LC_REGS \
: (REGNO) == REG_LB0 || (REGNO) == REG_LB1 ? LB_REGS \
: (REGNO) == REG_CC ? CCREGS \
: (REGNO) >= REG_RETS ? PROLOGUE_REGS \
: NO_REGS)

View File

@ -49,6 +49,9 @@
; B
; c (i0..i3,m0..m3) CIRCREGS
; C (CC) CCREGS
; t (lt0,lt1)
; k (lc0,lc1)
; l (lb0,lb1)
;
;; Define constants for hard registers.
@ -109,7 +112,14 @@
(REG_SEQSTAT 41)
(REG_USP 42)
(REG_ARGP 43)])
(REG_ARGP 43)
(REG_LT0 44)
(REG_LT1 45)
(REG_LC0 46)
(REG_LC1 47)
(REG_LB0 48)
(REG_LB1 49)])
;; Constants used in UNSPECs and UNSPEC_VOLATILEs.
@ -124,7 +134,8 @@
(UNSPEC_MUL_WITH_FLAG 6)
(UNSPEC_MAC_WITH_FLAG 7)
(UNSPEC_MOVE_FDPIC 8)
(UNSPEC_FUNCDESC_GOT17M4 9)])
(UNSPEC_FUNCDESC_GOT17M4 9)
(UNSPEC_LSETUP_END 10)])
(define_constants
[(UNSPEC_VOLATILE_EH_RETURN 0)
@ -243,6 +254,12 @@
(const_int 2)))
;; Classify the insns into those that are one instruction and those that
;; are more than one in sequence.
(define_attr "seq_insns" "single,multi"
(const_string "single"))
;; Conditional moves
(define_expand "movsicc"
@ -268,7 +285,8 @@
if cc %0 =%2; /* movsicc-1b */
if !cc %0 =%1; if cc %0=%2; /* movsicc-1 */"
[(set_attr "length" "2,2,4")
(set_attr "type" "move")])
(set_attr "type" "move")
(set_attr "seq_insns" "*,*,multi")])
(define_insn "*movsicc_insn2"
[(set (match_operand:SI 0 "register_operand" "=da,da,da")
@ -283,7 +301,8 @@
if cc %0 =%1; /* movsicc-2a */
if cc %0 =%1; if !cc %0=%2; /* movsicc-1 */"
[(set_attr "length" "2,2,4")
(set_attr "type" "move")])
(set_attr "type" "move")
(set_attr "seq_insns" "*,*,multi")])
;; Insns to load HIGH and LO_SUM
@ -376,7 +395,8 @@
%0 = CC;
R0 = R0 | R0; CC = AC0;"
[(set_attr "type" "move,mvi,mcld,mcst,compare,compare,alu0")
(set_attr "length" "2,2,*,*,2,2,4")])
(set_attr "length" "2,2,*,*,2,2,4")
(set_attr "seq_insns" "*,*,*,*,*,*,multi")])
(define_insn "movpdi"
[(set (match_operand:PDI 0 "nonimmediate_operand" "=e,<,e")
@ -386,7 +406,8 @@
%0 = %1;
%0 = %x1; %0 = %w1;
%w0 = %1; %x0 = %1;"
[(set_attr "type" "move,mcst,mcld")])
[(set_attr "type" "move,mcst,mcld")
(set_attr "seq_insns" "*,multi,multi")])
(define_insn "load_accumulator"
[(set (match_operand:PDI 0 "register_operand" "=e")
@ -429,12 +450,14 @@
;; The first alternative is used to make reload choose a limited register
;; class when faced with a movsi_insn that had its input operand replaced
;; with a PLUS. We generally require fewer secondary reloads this way.
(define_insn "*movsi_insn"
[(set (match_operand:SI 0 "nonimmediate_operand" "=da,x*y,da,x,x,x,da,mr")
(match_operand:SI 1 "general_operand" "da,x*y,xKs7,xKsh,xKuh,ix,mr,da"))]
(define_insn "*movsi_insn"
[(set (match_operand:SI 0 "nonimmediate_operand" "=da,x*y,*k,da,da,x,x,x,da,mr")
(match_operand:SI 1 "general_operand" "da,x*y,da,*k,xKs7,xKsh,xKuh,ix,mr,da"))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
"@
"@
%0 = %1;
%0 = %1;
%0 = %1;
%0 = %1;
%0 = %1 (X);
@ -443,8 +466,8 @@
#
%0 = %1;
%0 = %1;"
[(set_attr "type" "move,move,mvi,mvi,mvi,*,mcld,mcst")
(set_attr "length" "2,2,2,4,4,*,*,*")])
[(set_attr "type" "move,move,move,move,mvi,mvi,mvi,*,mcld,mcst")
(set_attr "length" "2,2,2,2,2,4,4,*,*,*")])
(define_insn_and_split "*movv2hi_insn"
[(set (match_operand:V2HI 0 "nonimmediate_operand" "=da,da,d,dm")
@ -776,7 +799,8 @@
(match_operand:DI 2 "register_operand" "d")))]
""
"%0 = %1 <op> %2;\\n\\t%H0 = %H1 <op> %H2;"
[(set_attr "length" "4")])
[(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
(define_insn "*<optab>di_zesidi_di"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -785,7 +809,8 @@
(match_operand:DI 1 "register_operand" "d")))]
""
"%0 = %1 <op> %2;\\n\\t%H0 = <high_result>;"
[(set_attr "length" "4")])
[(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
(define_insn "*<optab>di_sesdi_di"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -795,7 +820,8 @@
(clobber (match_scratch:SI 3 "=&d"))]
""
"%0 = %1 <op> %2;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %H1 <op> %3;"
[(set_attr "length" "8")])
[(set_attr "length" "8")
(set_attr "seq_insns" "multi")])
(define_insn "negdi2"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -804,14 +830,16 @@
(clobber (reg:CC REG_CC))]
""
"%2 = 0; %2 = %2 - %1; cc = ac0; cc = !cc; %2 = cc;\\n\\t%0 = -%1; %H0 = -%H1; %H0 = %H0 - %2;"
[(set_attr "length" "16")])
[(set_attr "length" "16")
(set_attr "seq_insns" "multi")])
(define_insn "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(not:DI (match_operand:DI 1 "register_operand" "d")))]
""
"%0 = ~%1;\\n\\t%H0 = ~%H1;"
[(set_attr "length" "4")])
[(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
;; DImode zero and sign extend patterns
@ -833,14 +861,16 @@
(zero_extend:DI (match_operand:QI 1 "register_operand" "d")))]
""
"%0 = %T1 (Z);\\n\\t%H0 = 0;"
[(set_attr "length" "4")])
[(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
(define_insn "zero_extendhidi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(zero_extend:DI (match_operand:HI 1 "register_operand" "d")))]
""
"%0 = %h1 (Z);\\n\\t%H0 = 0;"
[(set_attr "length" "4")])
[(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
(define_insn_and_split "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -896,7 +926,8 @@
%0 += %2; cc = ac0; %3 = cc; %H0 = %H0 + %3;
%0 = %0 + %2; cc = ac0; %3 = cc; %H0 = %H0 + %H2; %H0 = %H0 + %3;"
[(set_attr "type" "alu0")
(set_attr "length" "10,8,10")])
(set_attr "length" "10,8,10")
(set_attr "seq_insns" "multi,multi,multi")])
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=&d")
@ -905,7 +936,8 @@
(clobber (reg:CC 34))]
""
"%0 = %1-%2;\\n\\tcc = ac0;\\n\\t%H0 = %H1-%H2;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
[(set_attr "length" "10")])
[(set_attr "length" "10")
(set_attr "seq_insns" "multi")])
(define_insn "*subdi_di_zesidi"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -916,7 +948,8 @@
(clobber (reg:CC 34))]
""
"%0 = %1 - %2;\\n\\tcc = ac0;\\n\\tcc = ! cc;\\n\\t%3 = cc;\\n\\t%H0 = %H1 - %3;"
[(set_attr "length" "10")])
[(set_attr "length" "10")
(set_attr "seq_insns" "multi")])
(define_insn "*subdi_zesidi_di"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -927,7 +960,8 @@
(clobber (reg:CC 34))]
""
"%0 = %2 - %1;\\n\\tcc = ac0;\\n\\tcc = ! cc;\\n\\t%3 = cc;\\n\\t%3 = -%3;\\n\\t%H0 = %3 - %H1"
[(set_attr "length" "12")])
[(set_attr "length" "12")
(set_attr "seq_insns" "multi")])
(define_insn "*subdi_di_sesidi"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -938,7 +972,8 @@
(clobber (reg:CC 34))]
""
"%0 = %1 - %2;\\n\\tcc = ac0;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %H1 - %3;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
[(set_attr "length" "14")])
[(set_attr "length" "14")
(set_attr "seq_insns" "multi")])
(define_insn "*subdi_sesidi_di"
[(set (match_operand:DI 0 "register_operand" "=d")
@ -949,7 +984,8 @@
(clobber (reg:CC 34))]
""
"%0 = %2 - %1;\\n\\tcc = ac0;\\n\\t%3 = %2;\\n\\t%3 >>>= 31;\\n\\t%H0 = %3 - %H1;\\n\\tif cc jump 1f;\\n\\t%H0 += -1;\\n\\t1:"
[(set_attr "length" "14")])
[(set_attr "length" "14")
(set_attr "seq_insns" "multi")])
;; Combined shift/add instructions
@ -1496,6 +1532,89 @@
"jump (%0);"
[(set_attr "type" "misc")])
;; Hardware loop
; operand 0 is the loop count pseudo register
; operand 1 is the number of loop iterations or 0 if it is unknown
; operand 2 is the maximum number of loop iterations
; operand 3 is the number of levels of enclosed loops
; operand 4 is the label to jump to at the top of the loop
(define_expand "doloop_end"
[(parallel [(set (pc) (if_then_else
(ne (match_operand:SI 0 "" "")
(const_int 1))
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))
(unspec [(const_int 0)] UNSPEC_LSETUP_END)
(clobber (match_scratch:SI 5 ""))])]
""
{bfin_hardware_loop ();})
(define_insn "loop_end"
[(set (pc)
(if_then_else (ne (match_operand:SI 0 "nonimmediate_operand" "+a*d,*b*h*f,m")
(const_int 1))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus (match_dup 0)
(const_int -1)))
(unspec [(const_int 0)] UNSPEC_LSETUP_END)
(clobber (match_scratch:SI 2 "=X,&r,&r"))]
""
"@
/* loop end %0 %l1 */
#
#"
[(set_attr "length" "6,10,14")])
(define_split
[(set (pc)
(if_then_else (ne (match_operand:SI 0 "nondp_reg_or_memory_operand" "")
(const_int 1))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0)
(plus (match_dup 0)
(const_int -1)))
(unspec [(const_int 0)] UNSPEC_LSETUP_END)
(clobber (match_scratch:SI 2 "=&r"))]
"reload_completed"
[(set (match_dup 2) (match_dup 0))
(set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))
(set (match_dup 0) (match_dup 2))
(set (reg:BI REG_CC) (eq:BI (match_dup 2) (const_int 0)))
(set (pc)
(if_then_else (eq (reg:BI REG_CC)
(const_int 0))
(label_ref (match_dup 1))
(pc)))]
"")
(define_insn "lsetup_with_autoinit"
[(set (match_operand:SI 0 "lt_register_operand" "=t")
(label_ref (match_operand 1 "" "")))
(set (match_operand:SI 2 "lb_register_operand" "=l")
(label_ref (match_operand 3 "" "")))
(set (match_operand:SI 4 "lc_register_operand" "=k")
(match_operand:SI 5 "register_operand" "a"))]
""
"LSETUP (%1, %3) %4 = %5;"
[(set_attr "length" "4")])
(define_insn "lsetup_without_autoinit"
[(set (match_operand:SI 0 "lt_register_operand" "=t")
(label_ref (match_operand 1 "" "")))
(set (match_operand:SI 2 "lb_register_operand" "=l")
(label_ref (match_operand 3 "" "")))
(use (match_operand:SI 4 "lc_register_operand" "k"))]
""
"LSETUP (%1, %3) %4;"
[(set_attr "length" "4")])
;; Call instructions..
;; The explicit MEM inside the UNSPEC prevents the compiler from moving
@ -1760,11 +1879,15 @@
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 2))
(clobber (match_scratch:HI 5 "=&d"))]
(clobber (match_scratch:HI 5 "=&d"))
(clobber (reg:SI REG_LT1))
(clobber (reg:SI REG_LC1))
(clobber (reg:SI REG_LB1))]
""
"%5 = [%4++]; lsetup (1f, 1f) LC1 = %2; 1: MNOP || [%3++] = %5 || %5 = [%4++]; [%3++] = %5;"
[(set_attr "type" "misc")
(set_attr "length" "16")])
(set_attr "length" "16")
(set_attr "seq_insns" "multi")])
(define_insn "rep_movhi"
[(set (match_operand:SI 0 "register_operand" "=&a")
@ -1779,11 +1902,15 @@
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 2))
(clobber (match_scratch:HI 5 "=&d"))]
(clobber (match_scratch:HI 5 "=&d"))
(clobber (reg:SI REG_LT1))
(clobber (reg:SI REG_LC1))
(clobber (reg:SI REG_LB1))]
""
"%h5 = W[%4++]; lsetup (1f, 1f) LC1 = %2; 1: MNOP || W [%3++] = %5 || %h5 = W [%4++]; W [%3++] = %5;"
[(set_attr "type" "misc")
(set_attr "length" "16")])
(set_attr "length" "16")
(set_attr "seq_insns" "multi")])
(define_expand "movmemsi"
[(match_operand:BLK 0 "general_operand" "")
@ -2315,7 +2442,8 @@
""
"if !cc jump 4 (bp); excpt 3;"
[(set_attr "type" "misc")
(set_attr "length" "4")])
(set_attr "length" "4")
(set_attr "seq_insns" "multi")])
;;; Vector instructions

View File

@ -76,12 +76,44 @@
return 1;
})
;; Return nonzero if OP is a LC register.
(define_predicate "lc_register_operand"
(and (match_code "reg")
(match_test "REGNO (op) == REG_LC0 || REGNO (op) == REG_LC1")))
;; Return nonzero if OP is a LT register.
(define_predicate "lt_register_operand"
(and (match_code "reg")
(match_test "REGNO (op) == REG_LT0 || REGNO (op) == REG_LT1")))
;; Return nonzero if OP is a LB register.
(define_predicate "lb_register_operand"
(and (match_code "reg")
(match_test "REGNO (op) == REG_LB0 || REGNO (op) == REG_LB1")))
;; Return nonzero if OP is a register or a 7 bit signed constant.
(define_predicate "reg_or_7bit_operand"
(ior (match_operand 0 "register_operand")
(and (match_code "const_int")
(match_test "CONST_7BIT_IMM_P (INTVAL (op))"))))
;; Return nonzero if OP is a register other than DREG and PREG.
(define_predicate "nondp_register_operand"
(match_operand 0 "register_operand")
{
unsigned int regno;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
regno = REGNO (op);
return (regno >= FIRST_PSEUDO_REGISTER || !DP_REGNO_P (regno));
})
;; Return nonzero if OP is a register other than DREG and PREG, or MEM.
(define_predicate "nondp_reg_or_memory_operand"
(ior (match_operand 0 "nondp_register_operand")
(match_operand 0 "memory_operand")))
;; Used for secondary reloads, this function returns 1 if OP is of the
;; form (plus (fp) (const_int)).
(define_predicate "fp_plus_const_operand"