diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2005-07-28 02:03:45 +0000 |
---|---|---|
committer | Aldy Hernandez <aldyh@gcc.gnu.org> | 2005-07-28 02:03:45 +0000 |
commit | 38c28a2564a0f81eb26b2eec0908190c2094dd1f (patch) | |
tree | 86d74a60faadcae82333a3bbc29a7771ade8a80b /gcc/config/frv | |
parent | 47c504ea5ba6da768565dc25fd0455001cec7090 (diff) | |
download | gcc-38c28a2564a0f81eb26b2eec0908190c2094dd1f.zip gcc-38c28a2564a0f81eb26b2eec0908190c2094dd1f.tar.gz gcc-38c28a2564a0f81eb26b2eec0908190c2094dd1f.tar.bz2 |
frv.opt (moptimize-membar): New.
* 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.
From-SVN: r102455
Diffstat (limited to 'gcc/config/frv')
-rw-r--r-- | gcc/config/frv/frv.c | 458 | ||||
-rw-r--r-- | gcc/config/frv/frv.h | 7 | ||||
-rw-r--r-- | gcc/config/frv/frv.md | 44 | ||||
-rw-r--r-- | gcc/config/frv/frv.opt | 4 |
4 files changed, 429 insertions, 84 deletions
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index 756ae63..9213f9b 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -109,6 +109,21 @@ static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS]; /* The number of nop instructions in frv_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 instruction. */ #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode) @@ -123,6 +138,16 @@ static unsigned int frv_num_nops; REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \ 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. */ typedef struct frv_tmp_reg_struct { @@ -756,6 +781,9 @@ frv_override_options (void) if ((target_flags_explicit & MASK_LINKED_FP) == 0) 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++) 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) if (join_bb) { - int regno; + unsigned int regno; /* Remove anything live at the beginning of the join block from being available for allocation. */ @@ -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 insn = BB_HEAD (bb[j]); - int regno; + unsigned int regno; if (dump_file) 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) 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. */ static unsigned int frv_packet_address; @@ -7773,6 +8129,9 @@ frv_register_nop (rtx nop) static void frv_reorg (void) { + if (optimize > 0 && TARGET_OPTIMIZE_MEMBAR && cfun->machine->has_membar_p) + frv_optimize_membar (); + frv_num_nops = 0; frv_register_nop (gen_nop ()); if (TARGET_MEDIA) @@ -7953,33 +8312,33 @@ static struct builtin_description bdesc_voidacc[] = { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 } }; -/* Intrinsics that load a value and then issue a MEMBAR. - The FLAGS field is the icode for the membar. */ +/* Intrinsics that load a value and then issue a MEMBAR. The load is + a normal move and the ICODE is for the membar. */ static struct builtin_description bdesc_loads[] = { - { CODE_FOR_builtin_read_qi, "__builtin_read8", FRV_BUILTIN_READ8, 0, - CODE_FOR_optional_membar_qi }, - { CODE_FOR_builtin_read_hi, "__builtin_read16", FRV_BUILTIN_READ16, 0, - CODE_FOR_optional_membar_hi }, - { CODE_FOR_builtin_read_si, "__builtin_read32", FRV_BUILTIN_READ32, 0, - CODE_FOR_optional_membar_si }, - { CODE_FOR_builtin_read_di, "__builtin_read64", FRV_BUILTIN_READ64, 0, - CODE_FOR_optional_membar_di } + { CODE_FOR_optional_membar_qi, "__builtin_read8", + FRV_BUILTIN_READ8, 0, 0 }, + { CODE_FOR_optional_membar_hi, "__builtin_read16", + FRV_BUILTIN_READ16, 0, 0 }, + { CODE_FOR_optional_membar_si, "__builtin_read32", + FRV_BUILTIN_READ32, 0, 0 }, + { CODE_FOR_optional_membar_di, "__builtin_read64", + FRV_BUILTIN_READ64, 0, 0 } }; /* Likewise stores. */ static struct builtin_description bdesc_stores[] = { - { CODE_FOR_builtin_write_qi, "__builtin_write8", FRV_BUILTIN_WRITE8, 0, - CODE_FOR_optional_membar_qi }, - { CODE_FOR_builtin_write_hi, "__builtin_write16", FRV_BUILTIN_WRITE16, 0, - CODE_FOR_optional_membar_hi }, - { CODE_FOR_builtin_write_si, "__builtin_write32", FRV_BUILTIN_WRITE32, 0, - CODE_FOR_optional_membar_si }, - { CODE_FOR_builtin_write64, "__builtin_write64", FRV_BUILTIN_WRITE64, 0, - CODE_FOR_optional_membar_di } + { CODE_FOR_optional_membar_qi, "__builtin_write8", + FRV_BUILTIN_WRITE8, 0, 0 }, + { CODE_FOR_optional_membar_hi, "__builtin_write16", + FRV_BUILTIN_WRITE16, 0, 0 }, + { CODE_FOR_optional_membar_si, "__builtin_write32", + FRV_BUILTIN_WRITE32, 0, 0 }, + { CODE_FOR_optional_membar_di, "__builtin_write64", + FRV_BUILTIN_WRITE64, 0, 0 }, }; /* Initialize media builtins. */ @@ -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 register ACC. The mode of the returned register is in the same class as ACC, but is four times smaller. */ @@ -8670,36 +9041,38 @@ frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist) return NULL_RTX; } -/* Expand a __builtin_read* function. ICODE is the instruction code for - the load and MEMBAR_ICODE is the instruction code of the "membar". */ +/* Expand a __builtin_read* function. ICODE is the instruction code for the + membar and TARGET_MODE is the mode that the loaded value should have. */ static rtx -frv_expand_load_builtin (enum insn_code icode, enum insn_code membar_icode, - tree arglist, rtx target) +frv_expand_load_builtin (enum insn_code icode, enum machine_mode target_mode, + tree arglist, rtx target) { - rtx op0 = frv_read_argument (& arglist); - - target = frv_legitimize_target (icode, target); - op0 = frv_volatile_memref (insn_data[membar_icode].operand[0].mode, op0); - emit_insn (GEN_FCN (icode) (target, op0)); - emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0))); + rtx op0 = frv_read_argument (&arglist); + rtx cookie = frv_io_address_cookie (op0); + + if (target == 0 || !REG_P (target)) + target = gen_reg_rtx (target_mode); + 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; } -/* Likewise __builtin_write* functions, with ICODE being the instruction - code of the store. */ +/* Likewise __builtin_write* functions. */ static rtx -frv_expand_store_builtin (enum insn_code icode, enum insn_code membar_icode, - tree arglist) +frv_expand_store_builtin (enum insn_code icode, tree arglist) { - rtx op0 = frv_read_argument (& arglist); - rtx op1 = frv_read_argument (& arglist); + rtx op0 = 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); - op1 = frv_legitimize_argument (icode, 1, op1); - emit_insn (GEN_FCN (icode) (op0, op1)); - emit_insn (GEN_FCN (membar_icode) (copy_rtx (op0))); + op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0); + convert_move (op0, force_reg (insn_data[icode].operand[0].mode, op1), 1); + emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_WRITE))); + cfun->machine->has_membar_p = 1; return NULL_RTX; } @@ -9049,11 +9422,12 @@ frv_expand_builtin (tree exp, for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++) 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++) if (d->code == fcode) - return frv_expand_store_builtin (d->icode, d->flag, arglist); + return frv_expand_store_builtin (d->icode, arglist); return 0; } diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index 41c11c4..73ecb2a 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -1492,13 +1492,6 @@ typedef struct frv_stack { address of other frames. */ #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 /* A C expression whose value is RTL representing the location of the incoming diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md index 5b744bb..d0f3592 100644 --- a/gcc/config/frv/frv.md +++ b/gcc/config/frv/frv.md @@ -41,9 +41,7 @@ (UNSPEC_EH_RETURN_EPILOGUE 6) (UNSPEC_GOT 7) (UNSPEC_LDD 8) - (UNSPEC_BUILTIN_LOAD 9) - (UNSPEC_BUILTIN_STORE 10) - (UNSPEC_OPTIONAL_MEMBAR 11) + (UNSPEC_OPTIONAL_MEMBAR 9) (UNSPEC_GETTLSOFF 200) (UNSPEC_TLS_LOAD_GOTTLSOFF12 201) @@ -2168,41 +2166,17 @@ 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>" [(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" [(set_attr "length" "4")]) diff --git a/gcc/config/frv/frv.opt b/gcc/config/frv/frv.opt index 46d2381..7416dfa 100644 --- a/gcc/config/frv/frv.opt +++ b/gcc/config/frv/frv.opt @@ -157,6 +157,10 @@ mno-eflags Target RejectNegative Do not mark ABI switches in e_flags +moptimize-membar +Target Report Mask(OPTIMIZE_MEMBAR) +Remove redundant membars + mpack Target Report Mask(PACK) Pack VLIW instructions |