Commit 001b246b authored by aldyh's avatar aldyh
Browse files

* config/frv/frv.opt (moptimize-membar): New.

	* doc/invoke.texi: Document -moptimize-membar and its inverse.

	* config/frv/frv.h: Remove machine_function definition.

        * config/frv/frv.c (struct frv_io): New.
        (struct machine_function): Moved from frv.h.  Add has_membar_p.
        (frv_same_doubleword_p, frv_io_fixed_order_p, frv_io_union)
        (frv_extract_membar, frv_io_check_address, frv_io_handle_set)
        (frv_io_handle_use_1, frv_io_handle_use, frv_optimize_membar_local)
        (frv_optimize_membar_global, frv_optimize_membar): New functions.
        (frv_reorg): Call frv_optimize_membar when appropriate.
        (bdesc_loads, bdesc_stores): Use the membar code as the icode field.
        (frv_expand_builtin): Adjust calls accordingly.
        (frv_io_address_cookie): New function.
        (frv_expand_load_builtin, frv_expand_store_builtin): Emit a normal
        load or store rather than a special insn.  Add ccnstant address and
        io-type operands to the membar.
	(frv_ifcvt_modify_tests): Unsign regno.
	(frv_ifcvt_modify_tests): Same.

	* config/frv/frv.md: Remove UNSPEC_BUILTIN_{LOAD,STORE}.  Change
	UNSPEC_OPTIONAL_MEMBAR constant.
	(builtin_read_<mode>): Delete.
	(builtin_write_<mode>): Delete.
	("optional_membar_<mode>"): Add operand.

	* testsuite/gcc.target/frv/all-builtin-read8.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-read16.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-read32.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-read64.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-write8.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-write16.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-write32.c: Delete.
	* testsuite/gcc.target/frv/all-builtin-write64.c: Delete.
	* testsuite/gcc.target/frv/all-read-write-1.c: New.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102455 138bc75d-0d04-0410-961f-82ee72b054a4
parent 9cce384d
2005-07-27 Aldy Hernandez <aldyh@redhat.com>
* config/frv/frv.opt (moptimize-membar): New.
* doc/invoke.texi: Document -moptimize-membar and its inverse.
* config/frv/frv.h: Remove machine_function definition.
* config/frv/frv.c (struct frv_io): New.
(struct machine_function): Moved from frv.h. Add has_membar_p.
(frv_same_doubleword_p, frv_io_fixed_order_p, frv_io_union)
(frv_extract_membar, frv_io_check_address, frv_io_handle_set)
(frv_io_handle_use_1, frv_io_handle_use, frv_optimize_membar_local)
(frv_optimize_membar_global, frv_optimize_membar): New functions.
(frv_reorg): Call frv_optimize_membar when appropriate.
(bdesc_loads, bdesc_stores): Use the membar code as the icode field.
(frv_expand_builtin): Adjust calls accordingly.
(frv_io_address_cookie): New function.
(frv_expand_load_builtin, frv_expand_store_builtin): Emit a normal
load or store rather than a special insn. Add ccnstant address and
io-type operands to the membar.
(frv_ifcvt_modify_tests): Unsign regno.
(frv_ifcvt_modify_tests): Same.
* config/frv/frv.md: Remove UNSPEC_BUILTIN_{LOAD,STORE}. Change
UNSPEC_OPTIONAL_MEMBAR constant.
(builtin_read_<mode>): Delete.
(builtin_write_<mode>): Delete.
("optional_membar_<mode>"): Add operand.
* testsuite/gcc.target/frv/all-builtin-read8.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read16.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read32.c: Delete.
* testsuite/gcc.target/frv/all-builtin-read64.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write8.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write16.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write32.c: Delete.
* testsuite/gcc.target/frv/all-builtin-write64.c: Delete.
* testsuite/gcc.target/frv/all-read-write-1.c: New.
2005-07-28 Kaz Kojima <kkojima@gcc.gnu.org> 2005-07-28 Kaz Kojima <kkojima@gcc.gnu.org>
* df.c (df_uses_record): Handle SCRATCH. * df.c (df_uses_record): Handle SCRATCH.
......
...@@ -109,6 +109,21 @@ static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS]; ...@@ -109,6 +109,21 @@ static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
/* The number of nop instructions in frv_nops[]. */ /* The number of nop instructions in frv_nops[]. */
static unsigned int frv_num_nops; static unsigned int frv_num_nops;
/* Information about one __builtin_read or __builtin_write access, or
the combination of several such accesses. The most general value
is all-zeros (an unknown access to an unknown address). */
struct frv_io {
/* The type of access. FRV_IO_UNKNOWN means the access can be either
a read or a write. */
enum { FRV_IO_UNKNOWN, FRV_IO_READ, FRV_IO_WRITE } type;
/* The constant address being accessed, or zero if not known. */
HOST_WIDE_INT const_address;
/* The run-time address, as used in operand 0 of the membar pattern. */
rtx var_address;
};
/* Return true if instruction INSN should be packed with the following /* Return true if instruction INSN should be packed with the following
instruction. */ instruction. */
#define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode) #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
...@@ -123,6 +138,16 @@ static unsigned int frv_num_nops; ...@@ -123,6 +138,16 @@ static unsigned int frv_num_nops;
REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \ REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \
REG++) REG++)
/* This structure contains machine specific function data. */
struct machine_function GTY(())
{
/* True if we have created an rtx that relies on the stack frame. */
int frame_needed;
/* True if this function contains at least one __builtin_{read,write}*. */
bool has_membar_p;
};
/* Temporary register allocation support structure. */ /* Temporary register allocation support structure. */
typedef struct frv_tmp_reg_struct typedef struct frv_tmp_reg_struct
{ {
...@@ -756,6 +781,9 @@ frv_override_options (void) ...@@ -756,6 +781,9 @@ frv_override_options (void)
if ((target_flags_explicit & MASK_LINKED_FP) == 0) if ((target_flags_explicit & MASK_LINKED_FP) == 0)
target_flags |= MASK_LINKED_FP; target_flags |= MASK_LINKED_FP;
if ((target_flags_explicit & MASK_OPTIMIZE_MEMBAR) == 0)
target_flags |= MASK_OPTIMIZE_MEMBAR;
for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++) for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++)
frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]); frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]);
...@@ -5291,7 +5319,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false) ...@@ -5291,7 +5319,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
if (join_bb) if (join_bb)
{ {
int regno; unsigned int regno;
/* Remove anything live at the beginning of the join block from being /* Remove anything live at the beginning of the join block from being
available for allocation. */ available for allocation. */
...@@ -5328,7 +5356,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false) ...@@ -5328,7 +5356,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
{ {
rtx last_insn = BB_END (bb[j]); rtx last_insn = BB_END (bb[j]);
rtx insn = BB_HEAD (bb[j]); rtx insn = BB_HEAD (bb[j]);
int regno; unsigned int regno;
if (dump_file) if (dump_file)
fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n", fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
...@@ -7661,6 +7689,334 @@ frv_fill_unused_units (enum frv_insn_group group) ...@@ -7661,6 +7689,334 @@ frv_fill_unused_units (enum frv_insn_group group)
frv_insert_nop_in_packet (packet_group->nop); frv_insert_nop_in_packet (packet_group->nop);
} }
/* Return true if accesses IO1 and IO2 refer to the same doubleword. */
static bool
frv_same_doubleword_p (const struct frv_io *io1, const struct frv_io *io2)
{
if (io1->const_address != 0 && io2->const_address != 0)
return io1->const_address == io2->const_address;
if (io1->var_address != 0 && io2->var_address != 0)
return rtx_equal_p (io1->var_address, io2->var_address);
return false;
}
/* Return true if operations IO1 and IO2 are guaranteed to complete
in order. */
static bool
frv_io_fixed_order_p (const struct frv_io *io1, const struct frv_io *io2)
{
/* The order of writes is always preserved. */
if (io1->type == FRV_IO_WRITE && io2->type == FRV_IO_WRITE)
return true;
/* The order of reads isn't preserved. */
if (io1->type != FRV_IO_WRITE && io2->type != FRV_IO_WRITE)
return false;
/* One operation is a write and the other is (or could be) a read.
The order is only guaranteed if the accesses are to the same
doubleword. */
return frv_same_doubleword_p (io1, io2);
}
/* Generalize I/O operation X so that it covers both X and Y. */
static void
frv_io_union (struct frv_io *x, const struct frv_io *y)
{
if (x->type != y->type)
x->type = FRV_IO_UNKNOWN;
if (!frv_same_doubleword_p (x, y))
{
x->const_address = 0;
x->var_address = 0;
}
}
/* Fill IO with information about the load or store associated with
membar instruction INSN. */
static void
frv_extract_membar (struct frv_io *io, rtx insn)
{
extract_insn (insn);
io->type = INTVAL (recog_data.operand[2]);
io->const_address = INTVAL (recog_data.operand[1]);
io->var_address = XEXP (recog_data.operand[0], 0);
}
/* A note_stores callback for which DATA points to an rtx. Nullify *DATA
if X is a register and *DATA depends on X. */
static void
frv_io_check_address (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
{
rtx *other = data;
if (REG_P (x) && *other != 0 && reg_overlap_mentioned_p (x, *other))
*other = 0;
}
/* A note_stores callback for which DATA points to a HARD_REG_SET.
Remove every modified register from the set. */
static void
frv_io_handle_set (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
{
HARD_REG_SET *set = data;
unsigned int regno;
if (REG_P (x))
FOR_EACH_REGNO (regno, x)
CLEAR_HARD_REG_BIT (*set, regno);
}
/* A for_each_rtx callback for which DATA points to a HARD_REG_SET.
Add every register in *X to the set. */
static int
frv_io_handle_use_1 (rtx *x, void *data)
{
HARD_REG_SET *set = data;
unsigned int regno;
if (REG_P (*x))
FOR_EACH_REGNO (regno, *x)
SET_HARD_REG_BIT (*set, regno);
return 0;
}
/* A note_stores callback that applies frv_io_handle_use_1 to an
entire rhs value. */
static void
frv_io_handle_use (rtx *x, void *data)
{
for_each_rtx (x, frv_io_handle_use_1, data);
}
/* Go through block BB looking for membars to remove. There are two
cases where intra-block analysis is enough:
- a membar is redundant if it occurs between two consecutive I/O
operations and if those operations are guaranteed to complete
in order.
- a membar for a __builtin_read is redundant if the result is
used before the next I/O operation is issued.
If the last membar in the block could not be removed, and there
are guaranteed to be no I/O operations between that membar and
the end of the block, store the membar in *LAST_MEMBAR, otherwise
store null.
Describe the block's first I/O operation in *NEXT_IO. Describe
an unknown operation if the block doesn't do any I/O. */
static void
frv_optimize_membar_local (basic_block bb, struct frv_io *next_io,
rtx *last_membar)
{
HARD_REG_SET used_regs;
rtx next_membar, set, insn;
bool next_is_end_p;
/* NEXT_IO is the next I/O operation to be performed after the current
instruction. It starts off as being an unknown operation. */
memset (next_io, 0, sizeof (*next_io));
/* NEXT_IS_END_P is true if NEXT_IO describes the end of the block. */
next_is_end_p = true;
/* If the current instruction is a __builtin_read or __builtin_write,
NEXT_MEMBAR is the membar instruction associated with it. NEXT_MEMBAR
is null if the membar has already been deleted.
Note that the initialization here should only be needed to
supress warnings. */
next_membar = 0;
/* USED_REGS is the set of registers that are used before the
next I/O instruction. */
CLEAR_HARD_REG_SET (used_regs);
for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
/* We can't predict what a call will do to volatile memory. */
memset (next_io, 0, sizeof (struct frv_io));
next_is_end_p = false;
CLEAR_HARD_REG_SET (used_regs);
}
else if (INSN_P (insn))
switch (recog_memoized (insn))
{
case CODE_FOR_optional_membar_qi:
case CODE_FOR_optional_membar_hi:
case CODE_FOR_optional_membar_si:
case CODE_FOR_optional_membar_di:
next_membar = insn;
if (next_is_end_p)
{
/* Local information isn't enough to decide whether this
membar is needed. Stash it away for later. */
*last_membar = insn;
frv_extract_membar (next_io, insn);
next_is_end_p = false;
}
else
{
/* Check whether the I/O operation before INSN could be
reordered with one described by NEXT_IO. If it can't,
INSN will not be needed. */
struct frv_io prev_io;
frv_extract_membar (&prev_io, insn);
if (frv_io_fixed_order_p (&prev_io, next_io))
{
if (dump_file)
fprintf (dump_file,
";; [Local] Removing membar %d since order"
" of accesses is guaranteed\n",
INSN_UID (next_membar));
insn = NEXT_INSN (insn);
delete_insn (next_membar);
next_membar = 0;
}
*next_io = prev_io;
}
break;
default:
/* Invalidate NEXT_IO's address if it depends on something that
is clobbered by INSN. */
if (next_io->var_address)
note_stores (PATTERN (insn), frv_io_check_address,
&next_io->var_address);
/* If the next membar is associated with a __builtin_read,
see if INSN reads from that address. If it does, and if
the destination register is used before the next I/O access,
there is no need for the membar. */
set = PATTERN (insn);
if (next_io->type == FRV_IO_READ
&& next_io->var_address != 0
&& next_membar != 0
&& GET_CODE (set) == SET
&& GET_CODE (SET_DEST (set)) == REG
&& TEST_HARD_REG_BIT (used_regs, REGNO (SET_DEST (set))))
{
rtx src;
src = SET_SRC (set);
if (GET_CODE (src) == ZERO_EXTEND)
src = XEXP (src, 0);
if (GET_CODE (src) == MEM
&& rtx_equal_p (XEXP (src, 0), next_io->var_address))
{
if (dump_file)
fprintf (dump_file,
";; [Local] Removing membar %d since the target"
" of %d is used before the I/O operation\n",
INSN_UID (next_membar), INSN_UID (insn));
if (next_membar == *last_membar)
*last_membar = 0;
delete_insn (next_membar);
next_membar = 0;
}
}
/* If INSN has volatile references, forget about any registers
that are used after it. Otherwise forget about uses that
are (or might be) defined by INSN. */
if (volatile_refs_p (PATTERN (insn)))
CLEAR_HARD_REG_SET (used_regs);
else
note_stores (PATTERN (insn), frv_io_handle_set, &used_regs);
note_uses (&PATTERN (insn), frv_io_handle_use, &used_regs);
break;
}
}
/* See if MEMBAR, the last membar instruction in BB, can be removed.
FIRST_IO[X] describes the first operation performed by basic block X. */
static void
frv_optimize_membar_global (basic_block bb, struct frv_io *first_io,
rtx membar)
{
struct frv_io this_io, next_io;
edge succ;
edge_iterator ei;
/* We need to keep the membar if there is an edge to the exit block. */
FOR_EACH_EDGE (succ, ei, bb->succs)
/* for (succ = bb->succ; succ != 0; succ = succ->succ_next) */
if (succ->dest == EXIT_BLOCK_PTR)
return;
/* Work out the union of all successor blocks. */
ei = ei_start (bb->succs);
ei_cond (ei, &succ);
/* next_io = first_io[bb->succ->dest->index]; */
next_io = first_io[succ->dest->index];
ei = ei_start (bb->succs);
if (ei_cond (ei, &succ))
{
for (ei_next (&ei); ei_cond (ei, &succ); ei_next (&ei))
/*for (succ = bb->succ->succ_next; succ != 0; succ = succ->succ_next)*/
frv_io_union (&next_io, &first_io[succ->dest->index]);
}
else
gcc_unreachable ();
frv_extract_membar (&this_io, membar);
if (frv_io_fixed_order_p (&this_io, &next_io))
{
if (dump_file)
fprintf (dump_file,
";; [Global] Removing membar %d since order of accesses"
" is guaranteed\n", INSN_UID (membar));
delete_insn (membar);
}
}
/* Remove redundant membars from the current function. */
static void
frv_optimize_membar (void)
{
basic_block bb;
struct frv_io *first_io;
rtx *last_membar;
compute_bb_for_insn ();
first_io = xcalloc (last_basic_block, sizeof (struct frv_io));
last_membar = xcalloc (last_basic_block, sizeof (rtx));
FOR_EACH_BB (bb)
frv_optimize_membar_local (bb, &first_io[bb->index],
&last_membar[bb->index]);
FOR_EACH_BB (bb)
if (last_membar[bb->index] != 0)
frv_optimize_membar_global (bb, first_io, last_membar[bb->index]);
free (first_io);
free (last_membar);
}
/* Used by frv_reorg to keep track of the current packet's address. */ /* Used by frv_reorg to keep track of the current packet's address. */
static unsigned int frv_packet_address; static unsigned int frv_packet_address;
...@@ -7773,6 +8129,9 @@ frv_register_nop (rtx nop) ...@@ -7773,6 +8129,9 @@ frv_register_nop (rtx nop)
static void static void
frv_reorg (void) frv_reorg (void)
{ {
if (optimize > 0 && TARGET_OPTIMIZE_MEMBAR && cfun->machine->has_membar_p)
frv_optimize_membar ();
frv_num_nops = 0; frv_num_nops = 0;
frv_register_nop (gen_nop ()); frv_register_nop (gen_nop ());
if (TARGET_MEDIA) if (TARGET_MEDIA)
...@@ -7953,33 +8312,33 @@ static struct builtin_description bdesc_voidacc[] = ...@@ -7953,33 +8312,33 @@ static struct builtin_description bdesc_voidacc[] =
{ CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 } { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
}; };
/* Intrinsics that load a value and then issue a MEMBAR. /* Intrinsics that load a value and then issue a MEMBAR. The load is
The FLAGS field is the icode for the membar. */ a normal move and the ICODE is for the membar. */
static struct builtin_description bdesc_loads[] = static struct builtin_description bdesc_loads[] =
{ {
{ CODE_FOR_builtin_read_qi, "__builtin_read8", FRV_BUILTIN_READ8, 0, { CODE_FOR_optional_membar_qi, "__builtin_read8",
CODE_FOR_optional_membar_qi }, FRV_BUILTIN_READ8, 0, 0 },
{ CODE_FOR_builtin_read_hi, "__builtin_read16", FRV_BUILTIN_READ16, 0, { CODE_FOR_optional_membar_hi, "__builtin_read16",
CODE_FOR_optional_membar_hi }, FRV_BUILTIN_READ16, 0, 0 },
{ CODE_FOR_builtin_read_si, "__builtin_read32", FRV_BUILTIN_READ32, 0, { CODE_FOR_optional_membar_si, "__builtin_read32",
CODE_FOR_optional_membar_si }, FRV_BUILTIN_READ32, 0, 0 },
{ CODE_FOR_builtin_read_di, "__builtin_read64", FRV_BUILTIN_READ64, 0, { CODE_FOR_optional_membar_di, "__builtin_read64",
CODE_FOR_optional_membar_di } FRV_BUILTIN_READ64, 0, 0 }
}; };
/* Likewise stores. */ /* Likewise stores. */
static struct builtin_description bdesc_stores[] = static struct builtin_description bdesc_stores[] =
{ {
{ CODE_FOR_builtin_write_qi, "__builtin_write8", FRV_BUILTIN_WRITE8, 0, { CODE_FOR_optional_membar_qi, "__builtin_write8",
CODE_FOR_optional_membar_qi }, FRV_BUILTIN_WRITE8, 0, 0 },
{ CODE_FOR_builtin_write_hi, "__builtin_write16", FRV_BUILTIN_WRITE16, 0, { CODE_FOR_optional_membar_hi, "__builtin_write16",
CODE_FOR_optional_membar_hi }, FRV_BUILTIN_WRITE16, 0, 0 },
{ CODE_FOR_builtin_write_si, "__builtin_write32", FRV_BUILTIN_WRITE32, 0, { CODE_FOR_optional_membar_si, "__builtin_write32",
CODE_FOR_optional_membar_si }, FRV_BUILTIN_WRITE32, 0, 0 },
{ CODE_FOR_builtin_write64, "__builtin_write64", FRV_BUILTIN_WRITE64, 0, { CODE_FOR_optional_membar_di, "__builtin_write64",
CODE_FOR_optional_membar_di } FRV_BUILTIN_WRITE64, 0, 0 },
}; };
/* Initialize media builtins. */ /* Initialize media builtins. */
...@@ -8305,6 +8664,18 @@ frv_matching_accg_mode (enum machine_mode mode) ...@@ -8305,6 +8664,18 @@ frv_matching_accg_mode (enum machine_mode mode)
} }
} }
/* Given that a __builtin_read or __builtin_write function is accessing
address ADDRESS, return the value that should be used as operand 1
of the membar. */
static rtx
frv_io_address_cookie (rtx address)
{
return (GET_CODE (address) == CONST_INT
? GEN_INT (INTVAL (address) / 8 * 8)
: const0_rtx);
}
/* Return the accumulator guard that should be paired with accumulator /* Return the accumulator guard that should be paired with accumulator
register ACC. The mode of the returned register is in the same register ACC. The mode of the returned register is in the same
class as ACC, but is four times smaller. */ class as ACC, but is four times smaller. */
...@@ -8670,36 +9041,38 @@ frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist) ...@@ -8670,36 +9041,38 @@ frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
return NULL_RTX; return NULL_RTX;
} }
/* Expand a __builtin_read* function. ICODE is the instruction code for /* Expand a __builtin_read* function. ICODE is the instruction code for the
the load and MEMBAR_ICODE is the instruction code of the "membar". */ membar and TARGET_MODE is the mode that the loaded value should have. */
static rtx static rtx
frv_expand_load_builtin (enum insn_code icode, enum insn_code membar_icode, frv_expand_load_builtin (enum insn_code icode, enum machine_mode target_mode,
tree arglist, rtx target) tree arglist, rtx target)
{ {
rtx op0 = frv_read_argument (& arglist); rtx op0 = frv_read_argument (&arglist);
rtx cookie = frv_io_address_cookie (op0);
target = frv_legitimize_target (icode, target);
op0 = frv_volatile_memref (insn_data[membar_icode].operand[0].mode, op0); if (target == 0 || !REG_P (target))
emit_insn (GEN_FCN (icode) (target, op0)); target = gen_reg_rtx (target_mode);
emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0))); op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
convert_move (target, op0, 1);
emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_READ)));
cfun->machine->has_membar_p = 1;
return target; return target;
} }
/* Likewise __builtin_write* functions, with ICODE being the instruction /* Likewise __builtin_write* functions. */
code of the store. */
static rtx static rtx
frv_expand_store_builtin (enum insn_code icode, enum insn_code membar_icode, frv_expand_store_builtin (enum insn_code icode, tree arglist)
tree arglist)
{ {
rtx op0 = frv_read_argument (& arglist); rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (& arglist); rtx op1 = frv_read_argument (&arglist);
rtx cookie = frv_io_address_cookie (op0);
op0 = frv_volatile_memref (insn_data[membar_icode].operand[0].mode, op0); op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
op1 = frv_legitimize_argument (icode, 1, op1); convert_move (op0, force_reg (insn_data[icode].operand[0].mode, op1), 1);
emit_insn (GEN_FCN (icode) (op0, op1)); emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_WRITE)));
emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0))); cfun->machine->has_membar_p = 1;
return NULL_RTX; return NULL_RTX;
} }
...@@ -9049,11 +9422,12 @@ frv_expand_builtin (tree exp, ...@@ -9049,11 +9422,12 @@ frv_expand_builtin (tree exp,
for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++) for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++)
if (d->code == fcode) if (d->code == fcode)
return frv_expand_load_builtin (d->icode, d->flag, arglist, target); return frv_expand_load_builtin (d->icode, TYPE_MODE (TREE_TYPE (exp)),
arglist, target);
for (i = 0, d = bdesc_stores; i < ARRAY_SIZE (bdesc_stores); i++, d++) for (i = 0, d = bdesc_stores; i < ARRAY_SIZE (bdesc_stores); i++, d++)
if (d->code == fcode) if (d->code == fcode)
return frv_expand_store_builtin (d->icode, d->flag, arglist); return frv_expand_store_builtin (d->icode, arglist);
return 0; return 0;
} }
......
...@@ -1492,13 +1492,6 @@ typedef struct frv_stack { ...@@ -1492,13 +1492,6 @@ typedef struct frv_stack {
address of other frames. */ address of other frames. */
#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) frv_return_addr_rtx (COUNT, FRAMEADDR) #define RETURN_ADDR_RTX(COUNT, FRAMEADDR) frv_return_addr_rtx (COUNT, FRAMEADDR)
/* This function contains machine specific function data. */
struct machine_function GTY(())
{
/* True if we have created an rtx that relies on the stack frame. */
int frame_needed;
};
#define RETURN_POINTER_REGNUM LR_REGNO #define RETURN_POINTER_REGNUM LR_REGNO
/* A C expression whose value is RTL representing the location of the incoming /* A C expression whose value is RTL representing the location of the incoming
......
...@@ -41,9 +41,7 @@ ...@@ -41,9 +41,7 @@
(UNSPEC_EH_RETURN_EPILOGUE 6) (UNSPEC_EH_RETURN_EPILOGUE 6)
(UNSPEC_GOT 7) (UNSPEC_GOT 7)
(UNSPEC_LDD 8) (UNSPEC_LDD 8)
(UNSPEC_BUILTIN_LOAD 9) (UNSPEC_OPTIONAL_MEMBAR 9)
(UNSPEC_BUILTIN_STORE 10)
(UNSPEC_OPTIONAL_MEMBAR 11)
(UNSPEC_GETTLSOFF 200) (UNSPEC_GETTLSOFF 200)
(UNSPEC_TLS_LOAD_GOTTLSOFF12 201) (UNSPEC_TLS_LOAD_GOTTLSOFF12 201)
...@@ -2168,41 +2166,17 @@ ...@@ -2168,41 +2166,17 @@
FAIL; FAIL;
}") }")
;; The load part of a __builtin_read* function.
;; Use UNSPECs to distinguish these patterns from normal moves.
(define_insn "builtin_read_<mode>"
[(set (match_operand:SI 0 "register_operand" "=d")
(zero_extend:SI (unspec:IMODE
[(match_operand:IMODE 1 "memory_operand" "m")]
UNSPEC_BUILTIN_LOAD)))]
""
"ld<BREADsuffix>%I1%U1 %M1,%0"
[(set_attr "length" "4")
(set_attr "type" "gload")])
;; The store part of a __builtin_write* function.
(define_insn "builtin_write_<mode>"
[(set (match_operand:IMODE 0 "memory_operand" "=m")
(unspec:IMODE [(match_operand:IMODE 1 "reg_or_0_operand" "dO")]
UNSPEC_BUILTIN_STORE))]
""
"st<IMODEsuffix>%I0%U0 %z1, %M0"
[(set_attr "length" "4")
(set_attr "type" "gstore")])
;; This one has a different predicate for operand 1.
(define_insn "builtin_write64"
[(set (match_operand:DI 0 "memory_operand" "=m")
(unspec:DI [(match_operand:DI 1 "register_operand" "d")]
UNSPEC_BUILTIN_STORE))]
""
"std%I0%U0 %z1, %M0"
[(set_attr "length" "4")
(set_attr "type" "gstore")])
;; The "membar" part of a __builtin_read* or __builtin_write* function.
;; Operand 0 is a volatile reference to the memory that the function reads
;; or writes. Operand 1 is the address being accessed, or zero if the
;; address isn't a known constant. Operand 2 describes the __builtin
;; function (either FRV_IO_READ or FRV_IO_WRITE).
(define_insn "optional_membar_<mode>" (define_insn "optional_membar_<mode>"
[(set (match_operand:IMODE 0 "memory_operand" "=m") [(set (match_operand:IMODE 0 "memory_operand" "=m")
(unspec:IMODE [(const_int 0)] UNSPEC_OPTIONAL_MEMBAR))] (unspec:IMODE [(match_operand 1 "const_int_operand" "")
(match_operand 2 "const_int_operand" "")]
UNSPEC_OPTIONAL_MEMBAR))]
"" ""
"membar" "membar"
[(set_attr "length" "4")]) [(set_attr "length" "4")])
......
...@@ -157,6 +157,10 @@ mno-eflags ...@@ -157,6 +157,10 @@ mno-eflags
Target RejectNegative Target RejectNegative
Do not mark ABI switches in e_flags Do not mark ABI switches in e_flags
moptimize-membar
Target Report Mask(OPTIMIZE_MEMBAR)
Remove redundant membars
mpack mpack
Target Report Mask(PACK) Target Report Mask(PACK)
Pack VLIW instructions Pack VLIW instructions
......
...@@ -482,6 +482,7 @@ Objective-C and Objective-C++ Dialects}. ...@@ -482,6 +482,7 @@ Objective-C and Objective-C++ Dialects}.
-mlinked-fp -mlong-calls -malign-labels @gol -mlinked-fp -mlong-calls -malign-labels @gol
-mlibrary-pic -macc-4 -macc-8 @gol -mlibrary-pic -macc-4 -macc-8 @gol
-mpack -mno-pack -mno-eflags -mcond-move -mno-cond-move @gol -mpack -mno-pack -mno-eflags -mcond-move -mno-cond-move @gol
-moptimize-membar -mno-optimize-membar @gol
-mscc -mno-scc -mcond-exec -mno-cond-exec @gol -mscc -mno-scc -mcond-exec -mno-cond-exec @gol
-mvliw-branch -mno-vliw-branch @gol -mvliw-branch -mno-vliw-branch @gol
-mmulti-cond-exec -mno-multi-cond-exec -mnested-cond-exec @gol -mmulti-cond-exec -mno-multi-cond-exec -mnested-cond-exec @gol
...@@ -8526,6 +8527,18 @@ Disable nested conditional execution optimizations. ...@@ -8526,6 +8527,18 @@ Disable nested conditional execution optimizations.
This switch is mainly for debugging the compiler and will likely be removed This switch is mainly for debugging the compiler and will likely be removed
in a future version. in a future version.
@item -moptimize-membar
@opindex moptimize-membar
This switch removes redundant @code{membar} instructions from the
compiler generated code. It is enabled by default.
@item -mno-optimize-membar
@opindex mno-optimize-membar
This switch disables the automatic removal of redundant @code{membar}
instructions from the generated code.
@item -mtomcat-stats @item -mtomcat-stats
@opindex mtomcat-stats @opindex mtomcat-stats
......
/* { dg-do compile } */
unsigned short z;
void foo (void *x)
{
z = __builtin_read16 (x);
}
/* { dg-final { scan-assembler "lduh" } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
/* { dg-options "-O" } */
unsigned long z;
void foo (void *x)
{
z = __builtin_read32 (x);
}
/* { dg-final { scan-assembler "ld " } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned long long z;
void foo (void *x)
{
z = __builtin_read64 (x);
}
/* { dg-final { scan-assembler "ldd" } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned char z;
void foo (void *x)
{
z = __builtin_read8 (x);
}
/* { dg-final { scan-assembler "ldub" } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned short *addr;
unsigned short datum;
void foo ()
{
__builtin_write16 (addr, datum);
}
/* { dg-final { scan-assembler "sth" } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned long *addr;
unsigned long datum;
void foo ()
{
__builtin_write32 (addr, datum);
}
/* { dg-final { scan-assembler "st " } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned long long *addr;
unsigned long long datum;
void foo ()
{
__builtin_write64 (addr, datum);
}
/* { dg-final { scan-assembler "std " } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do compile } */
unsigned char *addr;
unsigned char datum;
void foo ()
{
__builtin_write8 (addr, datum);
}
/* { dg-final { scan-assembler "stb" } } */
/* { dg-final { scan-assembler "membar" } } */
/* { dg-do run } */
extern void abort (void);
extern void exit (int);
volatile unsigned long long x[2];
int main ()
{
volatile char *addr = (volatile char *) &x[0];
x[0] = ~0ULL;
x[1] = ~0ULL;
__builtin_write64 (addr, 0x1122334455667788ULL);
__builtin_write32 (addr + 8, 0x12345678);
__builtin_write16 (addr + 12, 0xaabb);
__builtin_write8 (addr + 14, 0xcc);
if (x[0] != 0x1122334455667788ULL
|| x[1] != 0x12345678aabbccffULL
|| __builtin_read8 (addr) != 0x11
|| __builtin_read16 (addr + 2) != 0x3344
|| __builtin_read32 (addr + 4) != 0x55667788
|| __builtin_read64 (addr + 8) != 0x12345678aabbccffULL)
abort ();
__builtin_write64 (addr, 0);
__builtin_write32 (addr + 8, 0);
__builtin_write16 (addr + 12, 0);
__builtin_write8 (addr + 14, 0);
if (x[0] != 0 || x[1] != 0xff)
abort ();
exit (0);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment