diff -urN gcc-27-2200/gcc/ChangeLog gcc-27-2300/gcc/ChangeLog --- gcc-27-2200/gcc/ChangeLog 2005-07-27 21:47:04.000000000 -0400 +++ gcc-27-2300/gcc/ChangeLog 2005-07-27 22:03:26.000000000 -0400 @@ -1,3 +1,43 @@ +2005-07-27 Aldy Hernandez + + * 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_): Delete. + (builtin_write_): Delete. + ("optional_membar_"): 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 * df.c (df_uses_record): Handle SCRATCH. diff -urN gcc-27-2200/gcc/config/frv/frv.c gcc-27-2300/gcc/config/frv/frv.c --- gcc-27-2200/gcc/config/frv/frv.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/config/frv/frv.c 2005-07-27 22:03:36.000000000 -0400 @@ -109,6 +109,21 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ { 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_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 @@ 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 @@ { 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 @@ } } +/* 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 @@ 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); + 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); - emit_insn (GEN_FCN (icode) (target, op0)); - emit_insn (GEN_FCN (membar_icode) (copy_rtx (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 @@ 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 -urN gcc-27-2200/gcc/config/frv/frv.h gcc-27-2300/gcc/config/frv/frv.h --- gcc-27-2200/gcc/config/frv/frv.h 2005-07-26 11:41:49.000000000 -0400 +++ gcc-27-2300/gcc/config/frv/frv.h 2005-07-27 22:03:36.000000000 -0400 @@ -1492,13 +1492,6 @@ 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 -urN gcc-27-2200/gcc/config/frv/frv.md gcc-27-2300/gcc/config/frv/frv.md --- gcc-27-2200/gcc/config/frv/frv.md 2005-07-26 11:41:49.000000000 -0400 +++ gcc-27-2300/gcc/config/frv/frv.md 2005-07-27 22:03:37.000000000 -0400 @@ -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_" - [(set (match_operand:SI 0 "register_operand" "=d") - (zero_extend:SI (unspec:IMODE - [(match_operand:IMODE 1 "memory_operand" "m")] - UNSPEC_BUILTIN_LOAD)))] - "" - "ld%I1%U1 %M1,%0" - [(set_attr "length" "4") - (set_attr "type" "gload")]) - -;; The store part of a __builtin_write* function. -(define_insn "builtin_write_" - [(set (match_operand:IMODE 0 "memory_operand" "=m") - (unspec:IMODE [(match_operand:IMODE 1 "reg_or_0_operand" "dO")] - UNSPEC_BUILTIN_STORE))] - "" - "st%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_" [(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 -urN gcc-27-2200/gcc/config/frv/frv.opt gcc-27-2300/gcc/config/frv/frv.opt --- gcc-27-2200/gcc/config/frv/frv.opt 2005-06-24 21:21:05.000000000 -0400 +++ gcc-27-2300/gcc/config/frv/frv.opt 2005-07-27 22:03:35.000000000 -0400 @@ -157,6 +157,10 @@ 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 diff -urN gcc-27-2200/gcc/doc/invoke.texi gcc-27-2300/gcc/doc/invoke.texi --- gcc-27-2200/gcc/doc/invoke.texi 2005-07-25 15:42:02.000000000 -0400 +++ gcc-27-2300/gcc/doc/invoke.texi 2005-07-27 22:03:37.000000000 -0400 @@ -482,6 +482,7 @@ -mlinked-fp -mlong-calls -malign-labels @gol -mlibrary-pic -macc-4 -macc-8 @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 -mvliw-branch -mno-vliw-branch @gol -mmulti-cond-exec -mno-multi-cond-exec -mnested-cond-exec @gol @@ -8526,6 +8527,18 @@ This switch is mainly for debugging the compiler and will likely be removed 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 @opindex mtomcat-stats diff -urN gcc-27-2200/gcc/testsuite/ChangeLog gcc-27-2300/gcc/testsuite/ChangeLog --- gcc-27-2200/gcc/testsuite/ChangeLog 2005-07-27 12:21:32.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/ChangeLog 2005-07-27 22:05:54.000000000 -0400 @@ -1,3 +1,15 @@ +2005-07-27 Aldy Hernandez + + * gcc.target/frv/all-builtin-read8.c: Delete. + * gcc.target/frv/all-builtin-read16.c: Delete. + * gcc.target/frv/all-builtin-read32.c: Delete. + * gcc.target/frv/all-builtin-read64.c: Delete. + * gcc.target/frv/all-builtin-write8.c: Delete. + * gcc.target/frv/all-builtin-write16.c: Delete. + * gcc.target/frv/all-builtin-write32.c: Delete. + * gcc.target/frv/all-builtin-write64.c: Delete. + * gcc.target/frv/all-read-write-1.c: New. + 2005-07-27 Jeff Law * gcc.c-torture/execute/pr22630.c: New test. diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read16.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read16.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read16.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read16.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,11 +0,0 @@ -/* { dg-do compile } */ - -unsigned short z; - -void foo (void *x) -{ - z = __builtin_read16 (x); -} - -/* { dg-final { scan-assembler "lduh" } } */ -/* { dg-final { scan-assembler "membar" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read32.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read32.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read32.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read32.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read64.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read64.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read64.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read64.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,11 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read8.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read8.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-read8.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-read8.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,11 +0,0 @@ -/* { dg-do compile } */ - -unsigned char z; - -void foo (void *x) -{ - z = __builtin_read8 (x); -} - -/* { dg-final { scan-assembler "ldub" } } */ -/* { dg-final { scan-assembler "membar" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write16.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write16.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write16.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write16.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write32.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write32.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write32.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write32.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write64.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write64.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write64.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write64.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write8.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write8.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-builtin-write8.c 2005-07-26 11:41:47.000000000 -0400 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-builtin-write8.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,12 +0,0 @@ -/* { 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" } } */ diff -urN gcc-27-2200/gcc/testsuite/gcc.target/frv/all-read-write-1.c gcc-27-2300/gcc/testsuite/gcc.target/frv/all-read-write-1.c --- gcc-27-2200/gcc/testsuite/gcc.target/frv/all-read-write-1.c 1969-12-31 19:00:00.000000000 -0500 +++ gcc-27-2300/gcc/testsuite/gcc.target/frv/all-read-write-1.c 2005-07-27 22:03:45.000000000 -0400 @@ -0,0 +1,34 @@ +/* { 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); +}