ms1.md (UNSPEC_LOOP): New constant.

* config/ms1/ms1.md (UNSPEC_LOOP): New constant.
	(loop_end, loop_init, doloop_end): New insns.
	* config/ms1/ms1.h (LOOP_FIRST, LOOP_LAST): New.
	(SPECIAL_REG_FIRST, FIRST_PSEUDO_REGISTER): Adjust.
	(FIXED_REGISTERS, CALL_USED_REGISTERS): Adjust.
	(REG_CLASS_CONTENTS, REGISTER_NAMES): Adjust.
	* config/ms1/ms1.c: #include basic-block.h
	(struct machine_function): Add has_loops field.
	(ms1_add_loop): New.
	(MAX_LOOP_DEPTH, MAX_LOO_LENGTH): New.
	(struct loop_info, struct loop_work): New.
	(ms1_loop_nesting, ms1_block_length, ms1_scan_loop): New workers.
	(ms1_reorg_loops): New loop optimization.
	(ms1_machine_reorg): Call it.
	* config/ms1/ms1-protos.h (ms1_add_loop): Declare.

From-SVN: r108229
This commit is contained in:
Nathan Sidwell 2005-12-08 13:46:18 +00:00 committed by Nathan Sidwell
parent bc9053abce
commit ac3ebe93b6
5 changed files with 597 additions and 13 deletions

View File

@ -1,3 +1,21 @@
2005-12-08 Nathan Sidwell <nathan@codesourcery.com>
* config/ms1/ms1.md (UNSPEC_LOOP): New constant.
(loop_end, loop_init, doloop_end): New insns.
* config/ms1/ms1.h (LOOP_FIRST, LOOP_LAST): New.
(SPECIAL_REG_FIRST, FIRST_PSEUDO_REGISTER): Adjust.
(FIXED_REGISTERS, CALL_USED_REGISTERS): Adjust.
(REG_CLASS_CONTENTS, REGISTER_NAMES): Adjust.
* config/ms1/ms1.c: #include basic-block.h
(struct machine_function): Add has_loops field.
(ms1_add_loop): New.
(MAX_LOOP_DEPTH, MAX_LOO_LENGTH): New.
(struct loop_info, struct loop_work): New.
(ms1_loop_nesting, ms1_block_length, ms1_scan_loop): New workers.
(ms1_reorg_loops): New loop optimization.
(ms1_machine_reorg): Call it.
* config/ms1/ms1-protos.h (ms1_add_loop): Declare.
2005-12-08 Zdenek Dvorak <dvorakz@suse.cz> 2005-12-08 Zdenek Dvorak <dvorakz@suse.cz>
PR tree-optimization/25248 PR tree-optimization/25248

View File

@ -26,6 +26,7 @@ extern void ms1_override_options (void);
extern int ms1_initial_elimination_offset (int, int); extern int ms1_initial_elimination_offset (int, int);
extern const char * ms1_asm_output_opcode (FILE *, const char *); extern const char * ms1_asm_output_opcode (FILE *, const char *);
extern int ms1_epilogue_uses (int); extern int ms1_epilogue_uses (int);
extern void ms1_add_loop (void);
#ifdef TREE_CODE #ifdef TREE_CODE
extern const char * ms1_cannot_inline_p (tree); extern const char * ms1_cannot_inline_p (tree);

View File

@ -47,6 +47,7 @@
#include "except.h" #include "except.h"
#include "target.h" #include "target.h"
#include "target-def.h" #include "target-def.h"
#include "basic-block.h"
/* Frame pointer register mask. */ /* Frame pointer register mask. */
#define FP_MASK (1 << (GPR_FP)) #define FP_MASK (1 << (GPR_FP))
@ -68,6 +69,7 @@ struct machine_function GTY(())
int ra_needs_full_frame; int ra_needs_full_frame;
struct rtx_def * eh_stack_adjust; struct rtx_def * eh_stack_adjust;
int interrupt_handler; int interrupt_handler;
int has_loops;
}; };
/* Define the information needed to generate branch and scc insns. /* Define the information needed to generate branch and scc insns.
@ -811,7 +813,7 @@ ms1_override_options (void)
error ("bad value (%s) for -march= switch", ms1_cpu_string); error ("bad value (%s) for -march= switch", ms1_cpu_string);
} }
else else
ms1_cpu = PROCESSOR_MS1_64_001; ms1_cpu = PROCESSOR_MS2;
if (flag_exceptions) if (flag_exceptions)
{ {
@ -1648,6 +1650,510 @@ ms1_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, tree type)
|| TREE_ADDRESSABLE (type)))); || TREE_ADDRESSABLE (type))));
} }
/* Increment the counter for the number of loop instructions in the
current function. */
void ms1_add_loop (void)
{
cfun->machine->has_loops++;
}
/* Maxium loop nesting depth. */
#define MAX_LOOP_DEPTH 4
/* Maxium size of a loop (allows some headroom for delayed branch slot
filling. */
#define MAX_LOOP_LENGTH (200 * 4)
/* We need to keep a vector of basic blocks */
DEF_VEC_P (basic_block);
DEF_VEC_ALLOC_P (basic_block,heap);
/* And 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 dbnz
insn. */
basic_block head;
/* Last block in the loop (the one with the dbnz insn */
basic_block tail;
/* The successor block of the loop. This is the one the dbnz insn
falls into. */
basic_block successor;
/* The dbnz insn. */
rtx dbnz;
/* The initialization insn. */
rtx init;
/* The new initialization instruction. */
rtx loop_init;
/* The new ending instruction. */
rtx loop_end;
/* The new label placed at the end of the loop. */
rtx end_label;
/* The nesting depth of the loop. Set to -1 for a bad loop. */
int depth;
/* The length of the loop. */
int length;
/* Next loop in the graph. */
struct loop_info *next;
/* 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);
/* Determine the nesting and length of LOOP. Return false if the loop
is bad. */
static bool
ms1_loop_nesting (loop_info loop)
{
loop_info inner;
unsigned ix;
int inner_depth = 0;
if (!loop->depth)
{
/* 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))
loop->predecessor = NULL;
}
/* Mark this loop as bad for now. */
loop->depth = -1;
if (loop->predecessor)
{
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix++, inner);)
{
if (!inner->depth)
ms1_loop_nesting (inner);
if (inner->depth < 0)
{
inner_depth = -1;
break;
}
if (inner_depth < inner->depth)
inner_depth = inner->depth;
loop->length += inner->length;
}
/* Set the proper loop depth, if it was good. */
if (inner_depth >= 0)
loop->depth = inner_depth + 1;
}
}
return (loop->depth > 0
&& loop->predecessor
&& loop->depth < MAX_LOOP_DEPTH
&& loop->length < MAX_LOOP_LENGTH);
}
/* Determine the length of block BB. */
static int
ms1_block_length (basic_block bb)
{
int length = 0;
rtx insn;
for (insn = BB_HEAD (bb);
insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
{
if (!INSN_P (insn))
continue;
if (CALL_P (insn))
{
/* Calls are not allowed in loops. */
length = MAX_LOOP_LENGTH + 1;
break;
}
length += get_attr_length (insn);
}
return length;
}
/* 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 dbnz
insn if it matches DBNZ. */
static bool
ms1_scan_loop (loop_info loop, rtx reg, rtx dbnz)
{
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 == dbnz)
continue;
if (reg_mentioned_p (reg, PATTERN (insn)))
return true;
}
}
for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
if (ms1_scan_loop (inner, reg, NULL_RTX))
return true;
return false;
}
/* MS2 has a loop instruction which needs to be placed just before the
loop. It indicates the end of the loop and specifies the number of
loop iterations. It can be nested with an automatically maintained
stack of counter and end address registers. It's an ideal
candidate for doloop. Unfortunately, gcc presumes that loops
always end with an explicit instriction, and the doloop_begin
instruction is not a flow control instruction so it can be
scheduled earlier than just before the start of the loop. To make
matters worse, the optimization pipeline can duplicate loop exit
and entrance blocks and fails to track abnormally exiting loops.
Thus we cannot simply use doloop.
What we do is emit a dbnz pattern for the doloop optimization, and
let that be optimized as normal. Then in machine dependent reorg
we have to repeat the loop searching algorithm. We use the
flow graph to find closed loops ending in a dbnz insn. We then try
and convert it to use the loop instruction. The conditions are,
* the loop has no abnormal exits, duplicated end conditions or
duplicated entrance blocks
* the loop counter register is only used in the dbnz instruction
within the loop
* we can find the instruction setting the initial value of the loop
counter
* the loop is not executed more than 65535 times. (This might be
changed to 2^32-1, and would therefore allow variable initializers.)
* the loop is not nested more than 4 deep 5) there are no
subroutine calls in the loop. */
static void
ms1_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;
bool replaced = false;
/* Find all the possible loop tails. This means searching for every
dbnz 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_decrement_and_branch_until_zero)
{
/* 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->dbnz = tail;
loop->depth = 0;
loop->length = ms1_block_length (bb);
loop->blocks = VEC_alloc (basic_block, heap, 20);
VEC_quick_push (basic_block, loop->blocks, bb);
loop->loops = NULL;
loop->loop_no = nloops++;
loop->init = loop->end_label = NULL_RTX;
loop->loop_init = loop->loop_end = 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;
loop->length += ms1_block_length (bb);
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
{
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);
/* Now optimize the loops. */
for (loop = loops; loop; loop = loop->next)
{
rtx iter_reg, insn, init_insn;
rtx init_val, loop_end, loop_init, end_label, head_label;
if (!ms1_loop_nesting (loop))
{
if (dump_file)
fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
continue;
}
/* Get the loop iteration register. */
iter_reg = SET_DEST (XVECEXP (PATTERN (loop->dbnz), 0, 1));
if (!REG_P (iter_reg))
{
/* Spilled */
if (dump_file)
fprintf (dump_file, ";; loop %d has spilled iteration count\n",
loop->loop_no);
continue;
}
/* Look for the initializing insn */
init_insn = NULL_RTX;
for (insn = BB_END (loop->predecessor);
insn != PREV_INSN (BB_HEAD (loop->predecessor));
insn = PREV_INSN (insn))
{
if (!INSN_P (insn))
continue;
if (reg_mentioned_p (iter_reg, PATTERN (insn)))
{
rtx set = single_set (insn);
if (set && rtx_equal_p (iter_reg, SET_DEST (set)))
init_insn = insn;
break;
}
}
if (!init_insn)
{
if (dump_file)
fprintf (dump_file, ";; loop %d has no initializer\n",
loop->loop_no);
continue;
}
if (dump_file)
{
fprintf (dump_file, ";; loop %d initialized by\n",
loop->loop_no);
print_rtl_single (dump_file, init_insn);
}
init_val = PATTERN (init_insn);
if (GET_CODE (init_val) == SET)
init_val = SET_SRC (init_val);
if (GET_CODE (init_val) != CONST_INT || INTVAL (init_val) >= 65535)
{
if (dump_file)
fprintf (dump_file, ";; loop %d has complex initializer\n",
loop->loop_no);
continue;
}
/* Scan all the blocks to make sure they don't use iter_reg. */
if (ms1_scan_loop (loop, iter_reg, loop->dbnz))
{
if (dump_file)
fprintf (dump_file, ";; loop %d uses iterator\n",
loop->loop_no);
continue;
}
/* The loop is good for replacement. */
/* loop is 1 based, dbnz is zero based. */
init_val = GEN_INT (INTVAL (init_val) + 1);
iter_reg = gen_rtx_REG (SImode, LOOP_FIRST + loop->depth - 1);
end_label = gen_label_rtx ();
head_label = XEXP (SET_SRC (XVECEXP (PATTERN (loop->dbnz), 0, 0)), 1);
loop_end = gen_loop_end (iter_reg, head_label);
loop_init = gen_loop_init (iter_reg, init_val, end_label);
loop->init = init_insn;
loop->end_label = end_label;
loop->loop_init = loop_init;
loop->loop_end = loop_end;
replaced = true;
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);
}
}
/* Now apply the optimizations. Do it this way so we don't mess up
the flow graph half way through. */
for (loop = loops; loop; loop = loop->next)
if (loop->loop_init)
{
emit_jump_insn_after (loop->loop_init, BB_END (loop->predecessor));
delete_insn (loop->init);
emit_label_before (loop->end_label, loop->dbnz);
emit_jump_insn_before (loop->loop_end, loop->dbnz);
delete_insn (loop->dbnz);
}
/* 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 (replaced && dump_file)
{
fprintf (dump_file, ";; Replaced loops\n");
print_rtl (dump_file, get_insns ());
}
}
/* Structures to hold branch information during reorg. */ /* Structures to hold branch information during reorg. */
typedef struct branch_info typedef struct branch_info
@ -1959,6 +2465,9 @@ ms1_reorg_hazard (void)
static void static void
ms1_machine_reorg (void) ms1_machine_reorg (void)
{ {
if (cfun->machine->has_loops)
ms1_reorg_loops (dump_file);
if (ms1_flag_delayed_branch) if (ms1_flag_delayed_branch)
dbr_schedule (get_insns (), dump_file); dbr_schedule (get_insns (), dump_file);

View File

@ -41,7 +41,7 @@ extern enum processor_type ms1_cpu;
/* A C string constant that tells the GCC driver program options to pass to /* A C string constant that tells the GCC driver program options to pass to
the assembler. */ the assembler. */
#undef ASM_SPEC #undef ASM_SPEC
#define ASM_SPEC "%{march=*} %{!march=*: -march=ms1-16-002}" #define ASM_SPEC "%{march=*} %{!march=*: -march=ms2}"
/* A string to pass to at the end of the command given to the linker. */ /* A string to pass to at the end of the command given to the linker. */
#undef LIB_SPEC #undef LIB_SPEC
@ -55,7 +55,7 @@ march=ms1-16-003:-T 16-003.ld%s; \
march=MS1-16-003:-T 16-003.ld%s; \ march=MS1-16-003:-T 16-003.ld%s; \
march=ms2:-T ms2.ld%s; \ march=ms2:-T ms2.ld%s; \
march=MS2:-T ms2.ld%s; \ march=MS2:-T ms2.ld%s; \
: -T 16-002.ld}" : -T ms2.ld}"
/* A string to pass at the very beginning of the command given to the /* A string to pass at the very beginning of the command given to the
linker. */ linker. */
@ -69,7 +69,7 @@ march=ms1-16-003:%{!mno-crt0:crt0-16-003.o%s} startup-16-003.o%s; \
march=MS1-16-003:%{!mno-crt0:crt0-16-003.o%s} startup-16-003.o%s; \ march=MS1-16-003:%{!mno-crt0:crt0-16-003.o%s} startup-16-003.o%s; \
march=ms2:%{!mno-crt0:crt0-ms2.o%s} startup-ms2.o%s; \ march=ms2:%{!mno-crt0:crt0-ms2.o%s} startup-ms2.o%s; \
march=MS2:%{!mno-crt0:crt0-ms2.o%s} startup-ms2.o%s; \ march=MS2:%{!mno-crt0:crt0-ms2.o%s} startup-ms2.o%s; \
:%{!mno-crt0:crt0-16-002.o%s} startup-16-002.o%s} \ :%{!mno-crt0:crt0-ms2.o%s} startup-ms2.o%s} \
crti.o%s crtbegin.o%s" crti.o%s crtbegin.o%s"
/* A string to pass at the end of the command given to the linker. */ /* A string to pass at the end of the command given to the linker. */
@ -83,7 +83,7 @@ march=ms1-16-003:exit-16-003.o%s; \
march=MS1-16-003:exit-16-003.o%s; \ march=MS1-16-003:exit-16-003.o%s; \
march=ms2:exit-ms2.o%s; \ march=ms2:exit-ms2.o%s; \
march=MS2:exit-ms2.o%s; \ march=MS2:exit-ms2.o%s; \
:exit-16-002.o%s} \ :exit-ms2.o%s} \
crtend.o%s crtn.o%s" crtend.o%s crtn.o%s"
/* Run-time target specifications. */ /* Run-time target specifications. */
@ -243,10 +243,13 @@ march=MS2:exit-ms2.o%s; \
seen by the caller */ seen by the caller */
#define GPR_INTERRUPT_LINK 15 /* hold return addres for interrupts */ #define GPR_INTERRUPT_LINK 15 /* hold return addres for interrupts */
#define LOOP_FIRST (GPR_LAST + 1)
#define LOOP_LAST (LOOP_FIRST + 3)
/* Argument register that is eliminated in favor of the frame and/or stack /* Argument register that is eliminated in favor of the frame and/or stack
pointer. Also add register to point to where the return address is pointer. Also add register to point to where the return address is
stored. */ stored. */
#define SPECIAL_REG_FIRST (GPR_LAST + 1) #define SPECIAL_REG_FIRST (LOOP_LAST + 1)
#define SPECIAL_REG_LAST (SPECIAL_REG_FIRST) #define SPECIAL_REG_LAST (SPECIAL_REG_FIRST)
#define ARG_POINTER_REGNUM (SPECIAL_REG_FIRST + 0) #define ARG_POINTER_REGNUM (SPECIAL_REG_FIRST + 0)
#define SPECIAL_REG_P(R) ((R) == SPECIAL_REG_FIRST) #define SPECIAL_REG_P(R) ((R) == SPECIAL_REG_FIRST)
@ -258,7 +261,7 @@ march=MS2:exit-ms2.o%s; \
/* The register used to hold functions return value */ /* The register used to hold functions return value */
#define RETVAL_REGNUM 11 #define RETVAL_REGNUM 11
#define FIRST_PSEUDO_REGISTER (GPR_FIRST + 17) #define FIRST_PSEUDO_REGISTER (SPECIAL_REG_LAST + 1)
#define IS_PSEUDO_P(R) (REGNO (R) >= FIRST_PSEUDO_REGISTER) #define IS_PSEUDO_P(R) (REGNO (R) >= FIRST_PSEUDO_REGISTER)
@ -270,7 +273,7 @@ march=MS2:exit-ms2.o%s; \
R15 IRA interrupt return address. */ R15 IRA interrupt return address. */
#define FIXED_REGISTERS { 1, 0, 0, 0, 0, 0, 0, 0, \ #define FIXED_REGISTERS { 1, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 1, 1, 1, 1, \ 0, 0, 0, 0, 1, 1, 1, 1, \
1 \ 1, 1, 1, 1, 1 \
} }
/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in /* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
@ -279,7 +282,7 @@ march=MS2:exit-ms2.o%s; \
allocation of values that must live across function calls. */ allocation of values that must live across function calls. */
#define CALL_USED_REGISTERS { 1, 1, 1, 1, 1, 0, 0, 1, \ #define CALL_USED_REGISTERS { 1, 1, 1, 1, 1, 0, 0, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \
1 \ 1, 1, 1, 1, 1 \
} }
@ -310,9 +313,9 @@ enum reg_class
#define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS" } #define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS" }
#define REG_CLASS_CONTENTS \ #define REG_CLASS_CONTENTS \
{ \ { \
{ 0x0, 0x0 }, \ { 0x0 }, \
{ (((1 << (GPR_LAST + 1)) - 1) & ~(1 << GPR_FIRST)), 0x0 }, \ { 0x000fffff }, \
} }
/* A C expression whose value is a register class containing hard register /* A C expression whose value is a register class containing hard register
@ -736,7 +739,7 @@ extern struct ms1_frame_info current_frame_info;
#define REGISTER_NAMES \ #define REGISTER_NAMES \
{ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \ { "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", \ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", \
"ap" } "LOOP1", "LOOP2", "LOOP3", "LOOP4", "ap" }
/* If defined, a C initializer for an array of structures containing a name and /* If defined, a C initializer for an array of structures containing a name and
a register number. This macro defines additional names for hard registers, a register number. This macro defines additional names for hard registers,

View File

@ -25,6 +25,7 @@
(UNSPEC_BLOCKAGE 0) (UNSPEC_BLOCKAGE 0)
(UNSPEC_EI 1) (UNSPEC_EI 1)
(UNSPEC_DI 2) (UNSPEC_DI 2)
(UNSPEC_LOOP 3)
]) ])
;; Attributes ;; Attributes
@ -148,6 +149,58 @@
"") "")
;; Loop instructions. ms2 has a low overhead looping instructions.
;; these take a constant or register loop count and a loop length
;; offset. Unfortunately the loop can only be up to 256 instructions,
;; We deal with longer loops by moving the loop end upwards. To do
;; otherwise would force us to to be very pessimistic right up until
;; the end.
;; This instruction is a placeholder to make the control flow explicit.
(define_insn "loop_end"
[(set (pc) (if_then_else
(ne (match_operand:SI 0 "register_operand" "")
(const_int 1))
(label_ref (match_operand 1 "" ""))
(pc)))
(set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))
(unspec [(const_int 0)] UNSPEC_LOOP)]
"TARGET_MS2"
";loop end %0,%l1"
[(set_attr "length" "0")])
;; This is the real looping instruction. It is placed just before the
;; loop body. We make it a branch insn, so it stays at the end of the
;; block it is in.
(define_insn "loop_init"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(match_operand:SI 1 "uns_arith_operand" "r,K"))
(unspec [(label_ref (match_operand 2 "" ""))] UNSPEC_LOOP)]
"TARGET_MS2"
"@
loop %1,%l2 ;%0%#
loopi %1,%l2 ;%0%#"
[(set_attr "length" "4")
(set_attr "type" "branch")])
; 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 "nonimmediate_operand" "")
(const_int 0))
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))
(clobber (match_scratch:SI 5 ""))])]
"TARGET_MS1_16_003 || TARGET_MS2"
{ms1_add_loop ();})
;; Moves ;; Moves
(define_expand "loadqi" (define_expand "loadqi"