diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 61 | ||||
-rw-r--r-- | gcc/config/mips/mips-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 424 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 264 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 48 | ||||
-rw-r--r-- | gcc/config/mips/sync.md | 321 |
6 files changed, 656 insertions, 466 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f50b14c18ad..f6d242b20ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,64 @@ +2009-08-26 Richard Sandiford <rdsandiford@googlemail.com> + + * config/mips/mips-protos.h (mips_output_sync): Declare. + (mips_sync_loop_insns): Likewise. + (mips_output_sync_loop): Replace first two parameters with an rtx. + * config/mips/mips.c (mips_multi_member): New structure. + (mips_multi_members): New variable. + (mips_multi_start): New function. + (mips_multi_add): Likewise. + (mips_multi_add_insn): Likewise. + (mips_multi_add_label): Likewise. + (mips_multi_last_index): Likewise. + (mips_multi_copy_insn): Likewise. + (mips_multi_set_operand): Likewise. + (mips_multi_write): Likewise. + (mips_print_operand_punctuation): Remove '%|' and '%-'. + (mips_init_print_operand_punct): Update accordingly. + (mips_start_ll_sc_sync_block): New function. + (mips_end_ll_sc_sync_block): Likewise. + (mips_output_sync): Likewise. + (mips_sync_insn1_template): Likewise. + (mips_sync_insn2_template): Likewise. + (mips_get_sync_operand): Likewise. + (mips_process_sync_loop): Likewise. + (mips_output_sync_loop): Use mips_process_sync_loop. + (mips_sync_loop_insns): New function. + * config/mips/mips.h (MIPS_COMPARE_AND_SWAP): Delete. + (MIPS_COMPARE_AND_SWAP_12): Likewise. + (MIPS_COMPARE_AND_SWAP_12_ZERO_OP): Likewise. + (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP): Likewise. + (MIPS_SYNC_OP, MIPS_SYNC_OP_12): Likewise. + (MIPS_SYNC_OP_12_AND, MIPS_SYNC_OP_12_XOR): Likewise. + (MIPS_SYNC_OLD_OP_12): Likewise. + (MIPS_SYNC_OLD_OP_12_AND, MIPS_SYNC_OLD_OP_12_XOR): Likewise. + (MIPS_SYNC_NEW_OP_12): Likewise. + (MIPS_SYNC_NEW_OP_12_AND, MIPS_SYNC_NEW_OP_12_XOR): Likewise. + (MIPS_SYNC_OLD_OP, MIPS_SYNC_NEW_OP): Likewise. + (MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND, MIPS_SYNC_NEW_NAND): Likewise. + (MIPS_SYNC_EXCHANGE, MIPS_SYNC_EXCHANGE_12): Likewise. + (MIPS_SYNC_EXCHANGE_12_ZERO_OP): Likewise. + (MIPS_SYNC_EXCHANGE_12_NONZER_OP): Likewise. + * config/mips/mips.md (sync_mem): New attribute. + (sync_oldval, sync_newval, sync_inclusive_mask): Likewise. + (sync_exclusive_mask, sync_required_oldval): Likewise. + (sync_insn1_op2, sync_insn1, sync_insn2): Likewise. + (sync_release_barrier): Likewise. + (length): Handle sync loops. + (sync): Use mips_output_sync. + * config/mips/sync.md (*memory_barrier): Use mips_output_sync. + (sync_compare_and_swap<mode>): Set the new sync_* attributes + and use mips_output_sync_loop. + (compare_and_swap_12, sync_add<mode>, sync_<optab>_12): Likewise. + (sync_old_<optab>_12, sync_new_<optab>_12, sync_nand_12): Likewise. + (sync_old_nand_12, sync_new_nand_12, sync_sub<mode>): Likewise. + (sync_old_add<mode>, sync_old_sub<mode>): Likewise. + (sync_new_add<mode>, sync_new_sub<mode>): Likewise. + (sync_<optab><mode>, sync_old_<optab><mode>): Likewise. + (sync_new_<optab><mode>, sync_nand<mode>): Likewise. + (sync_old_nand<mode>, sync_new_nand<mode>): Likewise. + (sync_lock_test_and_set<mode>, test_and_set_12): Likewise. + 2009-08-26 Richard Guenther <rguenther@suse.de> PR middle-end/41163 diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index d3502594221..a1e28ce23c6 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -300,7 +300,9 @@ extern const char *mips_output_load_label (void); extern const char *mips_output_conditional_branch (rtx, rtx *, const char *, const char *); extern const char *mips_output_order_conditional_branch (rtx, rtx *, bool); -extern const char *mips_output_sync_loop (bool, const char *, rtx *); +extern const char *mips_output_sync (void); +extern const char *mips_output_sync_loop (rtx, rtx *); +extern unsigned int mips_sync_loop_insns (rtx, rtx *); extern const char *mips_output_division (const char *, rtx *); extern unsigned int mips_hard_regno_nregs (int, enum machine_mode); extern bool mips_linked_madd_p (rtx, rtx); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 42363992376..1e4d8bd8ed5 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -3763,6 +3763,132 @@ mips_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) return mips_address_insns (addr, SImode, false); } +/* Information about a single instruction in a multi-instruction + asm sequence. */ +struct mips_multi_member { + /* True if this is a label, false if it is code. */ + bool is_label_p; + + /* The output_asm_insn format of the instruction. */ + const char *format; + + /* The operands to the instruction. */ + rtx operands[MAX_RECOG_OPERANDS]; +}; +typedef struct mips_multi_member mips_multi_member; + +/* Vector definitions for the above. */ +DEF_VEC_O(mips_multi_member); +DEF_VEC_ALLOC_O(mips_multi_member, heap); + +/* The instructions that make up the current multi-insn sequence. */ +static VEC (mips_multi_member, heap) *mips_multi_members; + +/* How many instructions (as opposed to labels) are in the current + multi-insn sequence. */ +static unsigned int mips_multi_num_insns; + +/* Start a new multi-insn sequence. */ + +static void +mips_multi_start (void) +{ + VEC_truncate (mips_multi_member, mips_multi_members, 0); + mips_multi_num_insns = 0; +} + +/* Add a new, uninitialized member to the current multi-insn sequence. */ + +static struct mips_multi_member * +mips_multi_add (void) +{ + return VEC_safe_push (mips_multi_member, heap, mips_multi_members, 0); +} + +/* Add a normal insn with the given asm format to the current multi-insn + sequence. The other arguments are a null-terminated list of operands. */ + +static void +mips_multi_add_insn (const char *format, ...) +{ + struct mips_multi_member *member; + va_list ap; + unsigned int i; + rtx op; + + member = mips_multi_add (); + member->is_label_p = false; + member->format = format; + va_start (ap, format); + i = 0; + while ((op = va_arg (ap, rtx))) + member->operands[i++] = op; + va_end (ap); + mips_multi_num_insns++; +} + +/* Add the given label definition to the current multi-insn sequence. + The definition should include the colon. */ + +static void +mips_multi_add_label (const char *label) +{ + struct mips_multi_member *member; + + member = mips_multi_add (); + member->is_label_p = true; + member->format = label; +} + +/* Return the index of the last member of the current multi-insn sequence. */ + +static unsigned int +mips_multi_last_index (void) +{ + return VEC_length (mips_multi_member, mips_multi_members) - 1; +} + +/* Add a copy of an existing instruction to the current multi-insn + sequence. I is the index of the instruction that should be copied. */ + +static void +mips_multi_copy_insn (unsigned int i) +{ + struct mips_multi_member *member; + + member = mips_multi_add (); + memcpy (member, VEC_index (mips_multi_member, mips_multi_members, i), + sizeof (*member)); + gcc_assert (!member->is_label_p); +} + +/* Change the operand of an existing instruction in the current + multi-insn sequence. I is the index of the instruction, + OP is the index of the operand, and X is the new value. */ + +static void +mips_multi_set_operand (unsigned int i, unsigned int op, rtx x) +{ + VEC_index (mips_multi_member, mips_multi_members, i)->operands[op] = x; +} + +/* Write out the asm code for the current multi-insn sequence. */ + +static void +mips_multi_write (void) +{ + struct mips_multi_member *member; + unsigned int i; + + for (i = 0; + VEC_iterate (mips_multi_member, mips_multi_members, i, member); + i++) + if (member->is_label_p) + fprintf (asm_out_file, "%s\n", member->format); + else + output_asm_insn (member->format, member->operands); +} + /* Return one word of double-word value OP, taking into account the fixed endianness of certain registers. HIGH_P is true to select the high part, false to select the low part. */ @@ -7047,8 +7173,6 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch) '^' Print the name of the pic call-through register (t9 or $25). '+' Print the name of the gp register (usually gp or $28). '$' Print the name of the stack pointer register (sp or $29). - '|' Print ".set push; .set mips2" if !ISA_HAS_LL_SC. - '-' Print ".set pop" under the same conditions for '|'. See also mips_init_print_operand_pucnt. */ @@ -7132,16 +7256,6 @@ mips_print_operand_punctuation (FILE *file, int ch) fputs (reg_names[STACK_POINTER_REGNUM], file); break; - case '|': - if (!ISA_HAS_LL_SC) - fputs (".set\tpush\n\t.set\tmips2\n\t", file); - break; - - case '-': - if (!ISA_HAS_LL_SC) - fputs ("\n\t.set\tpop", file); - break; - default: gcc_unreachable (); break; @@ -7155,7 +7269,7 @@ mips_init_print_operand_punct (void) { const char *p; - for (p = "()[]<>*#/?~.@^+$|-"; *p; p++) + for (p = "()[]<>*#/?~.@^+$"; *p; p++) mips_print_operand_punct[(unsigned char) *p] = true; } @@ -10808,31 +10922,279 @@ mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p) return mips_output_conditional_branch (insn, operands, branch[1], branch[0]); } -/* Return or emit the assembly code for __sync_*() loop LOOP. The - loop should support both normal and likely branches, using %? and - %~ where appropriate. If BARRIER_BEFORE is true a sync sequence is - emitted before the loop. A sync is always emitted after the loop. - OPERANDS are the insn operands. */ +/* Start a block of code that needs access to the LL, SC and SYNC + instructions. */ + +static void +mips_start_ll_sc_sync_block (void) +{ + if (!ISA_HAS_LL_SC) + { + output_asm_insn (".set\tpush", 0); + output_asm_insn (".set\tmips2", 0); + } +} + +/* End a block started by mips_start_ll_sc_sync_block. */ + +static void +mips_end_ll_sc_sync_block (void) +{ + if (!ISA_HAS_LL_SC) + output_asm_insn (".set\tpop", 0); +} + +/* Output and/or return the asm template for a sync instruction. */ const char * -mips_output_sync_loop (bool barrier_before, - const char *loop, rtx *operands) +mips_output_sync (void) { - if (barrier_before) - output_asm_insn ("sync", NULL); - /* Use branch-likely instructions to work around the LL/SC R10000 errata. */ - mips_branch_likely = TARGET_FIX_R10000; + mips_start_ll_sc_sync_block (); + output_asm_insn ("sync", 0); + mips_end_ll_sc_sync_block (); + return ""; +} - /* If the target needs a sync after the loop, emit the loop now and - return the sync. */ +/* Return the asm template associated with sync_insn1 value TYPE. + IS_64BIT_P is true if we want a 64-bit rather than 32-bit operation. */ - if (TARGET_SYNC_AFTER_SC) +static const char * +mips_sync_insn1_template (enum attr_sync_insn1 type, bool is_64bit_p) +{ + switch (type) + { + case SYNC_INSN1_MOVE: + return "move\t%0,%z2"; + case SYNC_INSN1_LI: + return "li\t%0,%2"; + case SYNC_INSN1_ADDU: + return is_64bit_p ? "daddu\t%0,%1,%z2" : "addu\t%0,%1,%z2"; + case SYNC_INSN1_ADDIU: + return is_64bit_p ? "daddiu\t%0,%1,%2" : "addiu\t%0,%1,%2"; + case SYNC_INSN1_SUBU: + return is_64bit_p ? "dsubu\t%0,%1,%z2" : "subu\t%0,%1,%z2"; + case SYNC_INSN1_AND: + return "and\t%0,%1,%z2"; + case SYNC_INSN1_ANDI: + return "andi\t%0,%1,%2"; + case SYNC_INSN1_OR: + return "or\t%0,%1,%z2"; + case SYNC_INSN1_ORI: + return "ori\t%0,%1,%2"; + case SYNC_INSN1_XOR: + return "xor\t%0,%1,%z2"; + case SYNC_INSN1_XORI: + return "xori\t%0,%1,%2"; + } + gcc_unreachable (); +} + +/* Return the asm template associated with sync_insn2 value TYPE. */ + +static const char * +mips_sync_insn2_template (enum attr_sync_insn2 type) +{ + switch (type) + { + case SYNC_INSN2_NOP: + gcc_unreachable (); + case SYNC_INSN2_AND: + return "and\t%0,%1,%z2"; + case SYNC_INSN2_XOR: + return "xor\t%0,%1,%z2"; + case SYNC_INSN2_NOT: + return "nor\t%0,%1,%."; + } + gcc_unreachable (); +} + +/* OPERANDS are the operands to a sync loop instruction and INDEX is + the value of the one of the sync_* attributes. Return the operand + referred to by the attribute, or DEFAULT_VALUE if the insn doesn't + have the associated attribute. */ + +static rtx +mips_get_sync_operand (rtx *operands, int index, rtx default_value) +{ + if (index > 0) + default_value = operands[index - 1]; + return default_value; +} + +/* INSN is a sync loop with operands OPERANDS. Build up a multi-insn + sequence for it. */ + +static void +mips_process_sync_loop (rtx insn, rtx *operands) +{ + rtx at, mem, oldval, newval, inclusive_mask, exclusive_mask; + rtx required_oldval, insn1_op2, tmp1, tmp2, tmp3; + unsigned int tmp3_insn; + enum attr_sync_insn1 insn1; + enum attr_sync_insn2 insn2; + bool is_64bit_p; + + /* Read an operand from the sync_WHAT attribute and store it in + variable WHAT. DEFAULT is the default value if no attribute + is specified. */ +#define READ_OPERAND(WHAT, DEFAULT) \ + WHAT = mips_get_sync_operand (operands, (int) get_attr_sync_##WHAT (insn), \ + DEFAULT) + + /* Read the memory. */ + READ_OPERAND (mem, 0); + gcc_assert (mem); + is_64bit_p = (GET_MODE_BITSIZE (GET_MODE (mem)) == 64); + + /* Read the other attributes. */ + at = gen_rtx_REG (GET_MODE (mem), AT_REGNUM); + READ_OPERAND (oldval, at); + READ_OPERAND (newval, at); + READ_OPERAND (inclusive_mask, 0); + READ_OPERAND (exclusive_mask, 0); + READ_OPERAND (required_oldval, 0); + READ_OPERAND (insn1_op2, 0); + insn1 = get_attr_sync_insn1 (insn); + insn2 = get_attr_sync_insn2 (insn); + + mips_multi_start (); + + /* Output the release side of the memory barrier. */ + if (get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES) + mips_multi_add_insn ("sync", NULL); + + /* Output the branch-back label. */ + mips_multi_add_label ("1:"); + + /* OLDVAL = *MEM. */ + mips_multi_add_insn (is_64bit_p ? "lld\t%0,%1" : "ll\t%0,%1", + oldval, mem, NULL); + + /* if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2. */ + if (required_oldval) + { + if (inclusive_mask == 0) + tmp1 = oldval; + else + { + gcc_assert (oldval != at); + mips_multi_add_insn ("and\t%0,%1,%2", + at, oldval, inclusive_mask, NULL); + tmp1 = at; + } + mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL); + } + + /* $TMP1 = OLDVAL & EXCLUSIVE_MASK. */ + if (exclusive_mask == 0) + tmp1 = const0_rtx; + else + { + gcc_assert (oldval != at); + mips_multi_add_insn ("and\t%0,%1,%z2", + at, oldval, exclusive_mask, NULL); + tmp1 = at; + } + + /* $TMP2 = INSN1 (OLDVAL, INSN1_OP2). + + We can ignore moves if $TMP4 != INSN1_OP2, since we'll still emit + at least one instruction in that case. */ + if (insn1 == SYNC_INSN1_MOVE + && (tmp1 != const0_rtx || insn2 != SYNC_INSN2_NOP)) + tmp2 = insn1_op2; + else { - output_asm_insn (loop, operands); - loop = "sync"; + mips_multi_add_insn (mips_sync_insn1_template (insn1, is_64bit_p), + newval, oldval, insn1_op2, NULL); + tmp2 = newval; } - - return loop; + + /* $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK). */ + if (insn2 == SYNC_INSN2_NOP) + tmp3 = tmp2; + else + { + mips_multi_add_insn (mips_sync_insn2_template (insn2), + newval, tmp2, inclusive_mask, NULL); + tmp3 = newval; + } + tmp3_insn = mips_multi_last_index (); + + /* $AT = $TMP1 | $TMP3. */ + if (tmp1 == const0_rtx || tmp3 == const0_rtx) + { + mips_multi_set_operand (tmp3_insn, 0, at); + tmp3 = at; + } + else + { + gcc_assert (tmp1 != tmp3); + mips_multi_add_insn ("or\t%0,%1,%2", at, tmp1, tmp3, NULL); + } + + /* if (!commit (*MEM = $AT)) goto 1. + + This will sometimes be a delayed branch; see the write code below + for details. */ + mips_multi_add_insn (is_64bit_p ? "scd\t%0,%1" : "sc\t%0,%1", at, mem, NULL); + mips_multi_add_insn ("beq%?\t%0,%.,1b", at, NULL); + + /* if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]. */ + if (insn1 != SYNC_INSN1_MOVE && insn1 != SYNC_INSN1_LI && tmp3 != newval) + { + mips_multi_copy_insn (tmp3_insn); + mips_multi_set_operand (mips_multi_last_index (), 0, newval); + } + else + mips_multi_add_insn ("nop", NULL); + + /* Output the acquire side of the memory barrier. */ + if (TARGET_SYNC_AFTER_SC) + mips_multi_add_insn ("sync", NULL); + + /* Output the exit label, if needed. */ + if (required_oldval) + mips_multi_add_label ("2:"); + +#undef READ_OPERAND +} + +/* Output and/or return the asm template for sync loop INSN, which has + the operands given by OPERANDS. */ + +const char * +mips_output_sync_loop (rtx insn, rtx *operands) +{ + mips_process_sync_loop (insn, operands); + + /* Use branch-likely instructions to work around the LL/SC R10000 + errata. */ + mips_branch_likely = TARGET_FIX_R10000; + + mips_push_asm_switch (&mips_noreorder); + mips_push_asm_switch (&mips_nomacro); + mips_push_asm_switch (&mips_noat); + mips_start_ll_sc_sync_block (); + + mips_multi_write (); + + mips_end_ll_sc_sync_block (); + mips_pop_asm_switch (&mips_noat); + mips_pop_asm_switch (&mips_nomacro); + mips_pop_asm_switch (&mips_noreorder); + + return ""; +} + +/* Return the number of individual instructions in sync loop INSN, + which has the operands given by OPERANDS. */ + +unsigned int +mips_sync_loop_insns (rtx insn, rtx *operands) +{ + mips_process_sync_loop (insn, operands); + return mips_multi_num_insns; } /* Return the assembly code for DIV or DDIV instruction DIVISION, which has diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 2c9199a12c3..352dbd25618 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -3113,270 +3113,6 @@ while (0) #define HAVE_AS_TLS 0 #endif -/* Return an asm string that atomically: - - - Compares memory reference %1 to register %2 and, if they are - equal, changes %1 to %3. - - - Sets register %0 to the old value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" instructions - and OP is the instruction that should be used to load %3 into a - register. */ -#define MIPS_COMPARE_AND_SWAP(SUFFIX, OP) \ - "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n" \ - "\tbne\t%0,%z2,2f\n" \ - "\t" OP "\t%@,%3\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)\n" \ - "2:\n" - -/* Return an asm string that atomically: - - - Given that %2 contains a bit mask and %3 the inverted mask and - that %4 and %5 have already been ANDed with %2. - - - Compares the bits in memory reference %1 selected by mask %2 to - register %4 and, if they are equal, changes the selected bits - in memory to %5. - - - Sets register %0 to the old value of memory reference %1. - - OPS are the instructions needed to OR %5 with %@. */ -#define MIPS_COMPARE_AND_SWAP_12(OPS) \ - "%(%<%[%|1:\tll\t%0,%1\n" \ - "\tand\t%@,%0,%2\n" \ - "\tbne\t%@,%z4,2f\n" \ - "\tand\t%@,%0,%3\n" \ - OPS \ - "\tsc\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)\n" \ - "2:\n" - -#define MIPS_COMPARE_AND_SWAP_12_ZERO_OP "" -#define MIPS_COMPARE_AND_SWAP_12_NONZERO_OP "\tor\t%@,%@,%5\n" - - -/* Return an asm string that atomically: - - - Sets memory reference %0 to %0 INSN %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. */ -#define MIPS_SYNC_OP(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%@,%0\n" \ - "\t" INSN "\t%@,%@,%1\n" \ - "\tsc" SUFFIX "\t%@,%0\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -/* Return an asm string that atomically: - - - Given that %1 contains a bit mask and %2 the inverted mask and - that %3 has already been ANDed with %1. - - - Sets the selected bits of memory reference %0 to %0 INSN %3. - - - Uses scratch register %4. - - AND_OP is an instruction done after INSN to mask INSN's result - with the mask. For most operations, this is an AND with the - inclusive mask (%1). For nand operations -- where the result of - INSN is already correctly masked -- it instead performs a bitwise - not. */ -#define MIPS_SYNC_OP_12(INSN, AND_OP) \ - "%(%<%[%|1:\tll\t%4,%0\n" \ - "\tand\t%@,%4,%2\n" \ - "\t" INSN "\t%4,%4,%z3\n" \ - AND_OP \ - "\tor\t%@,%@,%4\n" \ - "\tsc\t%@,%0\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -#define MIPS_SYNC_OP_12_AND "\tand\t%4,%4,%1\n" -#define MIPS_SYNC_OP_12_XOR "\txor\t%4,%4,%1\n" - -/* Return an asm string that atomically: - - - Given that %2 contains a bit mask and %3 the inverted mask and - that %4 has already been ANDed with %2. - - - Sets the selected bits of memory reference %1 to %1 INSN %4. - - - Sets %0 to the original value of %1. - - - Uses scratch register %5. - - AND_OP is an instruction done after INSN to mask INSN's result - with the mask. For most operations, this is an AND with the - inclusive mask (%1). For nand operations -- where the result of - INSN is already correctly masked -- it instead performs a bitwise - not. */ -#define MIPS_SYNC_OLD_OP_12(INSN, AND_OP) \ - "%(%<%[%|1:\tll\t%0,%1\n" \ - "\tand\t%@,%0,%3\n" \ - "\t" INSN "\t%5,%0,%z4\n" \ - AND_OP \ - "\tor\t%@,%@,%5\n" \ - "\tsc\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -#define MIPS_SYNC_OLD_OP_12_AND "\tand\t%5,%5,%2\n" -#define MIPS_SYNC_OLD_OP_12_XOR "\txor\t%5,%5,%2\n" - -/* Return an asm string that atomically: - - - Given that %2 contains a bit mask and %3 the inverted mask and - that %4 has already been ANDed with %2. - - - Sets the selected bits of memory reference %1 to %1 INSN %4. - - - Sets %0 to the new value of %1. - - AND_OP is an instruction done after INSN to mask INSN's result - with the mask. For most operations, this is an AND with the - inclusive mask (%1). For nand operations -- where the result of - INSN is already correctly masked -- it instead performs a bitwise - not. */ -#define MIPS_SYNC_NEW_OP_12(INSN, AND_OP) \ - "%(%<%[%|1:\tll\t%0,%1\n" \ - "\tand\t%@,%0,%3\n" \ - "\t" INSN "\t%0,%0,%z4\n" \ - AND_OP \ - "\tor\t%@,%@,%0\n" \ - "\tsc\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -#define MIPS_SYNC_NEW_OP_12_AND "\tand\t%0,%0,%2\n" -#define MIPS_SYNC_NEW_OP_12_XOR "\txor\t%0,%0,%2\n" - -/* Return an asm string that atomically: - - - Sets memory reference %1 to %1 INSN %2. - - - Sets register %0 to the old value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. */ -#define MIPS_SYNC_OLD_OP(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n" \ - "\t" INSN "\t%@,%0,%2\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -/* Return an asm string that atomically: - - - Sets memory reference %1 to %1 INSN %2. - - - Sets register %0 to the new value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. */ -#define MIPS_SYNC_NEW_OP(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n" \ - "\t" INSN "\t%@,%0,%2\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b%~\n" \ - "\t" INSN "\t%0,%0,%2%-%]%>%)" - -/* Return an asm string that atomically: - - - Sets memory reference %0 to ~(%0 AND %1). - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. INSN is the and instruction needed to and a register - with %2. */ -#define MIPS_SYNC_NAND(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%@,%0\n" \ - "\t" INSN "\t%@,%@,%1\n" \ - "\tnor\t%@,%@,%.\n" \ - "\tsc" SUFFIX "\t%@,%0\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -/* Return an asm string that atomically: - - - Sets memory reference %1 to ~(%1 AND %2). - - - Sets register %0 to the old value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. INSN is the and instruction needed to and a register - with %2. */ -#define MIPS_SYNC_OLD_NAND(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n" \ - "\t" INSN "\t%@,%0,%2\n" \ - "\tnor\t%@,%@,%.\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -/* Return an asm string that atomically: - - - Sets memory reference %1 to ~(%1 AND %2). - - - Sets register %0 to the new value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. INSN is the and instruction needed to and a register - with %2. */ -#define MIPS_SYNC_NEW_NAND(SUFFIX, INSN) \ - "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n" \ - "\t" INSN "\t%0,%0,%2\n" \ - "\tnor\t%@,%0,%.\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b%~\n" \ - "\tnor\t%0,%0,%.%-%]%>%)" - -/* Return an asm string that atomically: - - - Sets memory reference %1 to %2. - - - Sets register %0 to the old value of memory reference %1. - - SUFFIX is the suffix that should be added to "ll" and "sc" - instructions. OP is the and instruction that should be used to - load %2 into a register. */ -#define MIPS_SYNC_EXCHANGE(SUFFIX, OP) \ - "%(%<%[%|\n" \ - "1:\tll" SUFFIX "\t%0,%1\n" \ - "\t" OP "\t%@,%2\n" \ - "\tsc" SUFFIX "\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -/* Return an asm string that atomically: - - - Given that %2 contains an inclusive mask, %3 and exclusive mask - and %4 has already been ANDed with the inclusive mask. - - - Sets bits selected by the inclusive mask of memory reference %1 - to %4. - - - Sets register %0 to the old value of memory reference %1. - - OPS are the instructions needed to OR %4 with %@. - - Operand %2 is unused, but needed as to give the test_and_set_12 - insn the five operands expected by the expander. */ -#define MIPS_SYNC_EXCHANGE_12(OPS) \ - "%(%<%[%|\n" \ - "1:\tll\t%0,%1\n" \ - "\tand\t%@,%0,%3\n" \ - OPS \ - "\tsc\t%@,%1\n" \ - "\tbeq%?\t%@,%.,1b\n" \ - "\tnop%-%]%>%)" - -#define MIPS_SYNC_EXCHANGE_12_ZERO_OP "" -#define MIPS_SYNC_EXCHANGE_12_NONZERO_OP "\tor\t%@,%@,%4\n" - #ifndef USED_FOR_TARGET /* Information about ".set noFOO; ...; .set FOO" blocks. */ struct mips_asm_switch { diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 92363b3b59c..a510e0a7b74 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -449,6 +449,49 @@ (const_string "yes") (const_string "no"))) +;; Attributes describing a sync loop. These loops have the form: +;; +;; if (RELEASE_BARRIER == YES) sync +;; 1: OLDVAL = *MEM +;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2 +;; $TMP1 = OLDVAL & EXCLUSIVE_MASK +;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2) +;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK) +;; $AT |= $TMP1 | $TMP3 +;; if (!commit (*MEM = $AT)) goto 1. +;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot] +;; sync +;; 2: +;; +;; where "$" values are temporaries and where the other values are +;; specified by the attributes below. Values are specified as operand +;; numbers and insns are specified as enums. If no operand number is +;; specified, the following values are used instead: +;; +;; - OLDVAL: $AT +;; - NEWVAL: $AT +;; - INCLUSIVE_MASK: -1 +;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK +;; - EXCLUSIVE_MASK: 0 +;; +;; MEM and INSN1_OP2 are required. +;; +;; Ideally, the operand attributes would be integers, with -1 meaning "none", +;; but the gen* programs don't yet support that. +(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_required_oldval" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_insn1_op2" "none,0,1,2,3,4,5" (const_string "none")) +(define_attr "sync_insn1" "move,li,addu,addiu,subu,and,andi,or,ori,xor,xori" + (const_string "move")) +(define_attr "sync_insn2" "nop,and,xor,not" + (const_string "nop")) +(define_attr "sync_release_barrier" "yes,no" + (const_string "yes")) + ;; Length of instruction in bytes. (define_attr "length" "" (cond [(and (eq_attr "extended_mips16" "yes") @@ -572,6 +615,9 @@ (eq_attr "type" "idiv,idiv3") (symbol_ref "mips_idiv_insns () * 4") + + (not (eq_attr "sync_mem" "none")) + (symbol_ref "mips_sync_loop_insns (insn, operands) * 4") ] (const_int 4))) ;; Attribute describing the processor. This attribute must match exactly @@ -4826,7 +4872,7 @@ (define_insn "sync" [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] "GENERATE_SYNC" - "%|sync%-") + { return mips_output_sync (); }) (define_insn "synci" [(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")] diff --git a/gcc/config/mips/sync.md b/gcc/config/mips/sync.md index affb3faff75..e28f56c601a 100644 --- a/gcc/config/mips/sync.md +++ b/gcc/config/mips/sync.md @@ -40,7 +40,7 @@ [(set (match_operand:BLK 0 "" "") (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] "GENERATE_SYNC" - "%|sync%-") + { return mips_output_sync (); }) (define_insn "sync_compare_and_swap<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -50,15 +50,12 @@ (match_operand:GPR 3 "arith_operand" "I,d")] UNSPEC_COMPARE_AND_SWAP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_COMPARE_AND_SWAP ("<d>", "li"); - else - loop = MIPS_COMPARE_AND_SWAP ("<d>", "move"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "32")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "li,move") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_required_oldval" "2") + (set_attr "sync_insn1_op2" "3")]) (define_expand "sync_compare_and_swap<mode>" [(match_operand:SHORT 0 "register_operand") @@ -85,15 +82,13 @@ (match_operand:SI 5 "reg_or_0_operand" "d,J")] UNSPEC_COMPARE_AND_SWAP_12))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP); - else - loop = MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_ZERO_OP); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40,36")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_required_oldval" "4") + (set_attr "sync_insn1_op2" "5")]) (define_insn "sync_add<mode>" [(set (match_operand:GPR 0 "memory_operand" "+R,R") @@ -102,15 +97,10 @@ (match_operand:GPR 1 "arith_operand" "I,d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_OP ("<d>", "<d>addiu"); - else - loop = MIPS_SYNC_OP ("<d>", "<d>addu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "addiu,addu") + (set_attr "sync_mem" "0") + (set_attr "sync_insn1_op2" "1")]) (define_expand "sync_<optab><mode>" [(set (match_operand:SHORT 0 "memory_operand") @@ -138,11 +128,15 @@ UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 4 "=&d"))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OP_12 ("<insn>", MIPS_SYNC_OP_12_AND); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<insn>") + (set_attr "sync_insn2" "and") + (set_attr "sync_mem" "0") + (set_attr "sync_inclusive_mask" "1") + (set_attr "sync_exclusive_mask" "2") + (set_attr "sync_insn1_op2" "3") + (set_attr "sync_oldval" "4") + (set_attr "sync_newval" "4")]) (define_expand "sync_old_<optab><mode>" [(parallel [ @@ -175,11 +169,15 @@ UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 5 "=&d"))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OLD_OP_12 ("<insn>", MIPS_SYNC_OLD_OP_12_AND); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<insn>") + (set_attr "sync_insn2" "and") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_insn1_op2" "4") + (set_attr "sync_newval" "5")]) (define_expand "sync_new_<optab><mode>" [(parallel [ @@ -217,11 +215,15 @@ (match_dup 3) (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_NEW_OP_12 ("<insn>", MIPS_SYNC_NEW_OP_12_AND); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<insn>") + (set_attr "sync_insn2" "and") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_insn1_op2" "4")]) (define_expand "sync_nand<mode>" [(set (match_operand:SHORT 0 "memory_operand") @@ -249,11 +251,15 @@ UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 4 "=&d"))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OP_12 ("and", MIPS_SYNC_OP_12_XOR); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "and") + (set_attr "sync_insn2" "xor") + (set_attr "sync_mem" "0") + (set_attr "sync_inclusive_mask" "1") + (set_attr "sync_exclusive_mask" "2") + (set_attr "sync_insn1_op2" "3") + (set_attr "sync_oldval" "4") + (set_attr "sync_newval" "4")]) (define_expand "sync_old_nand<mode>" [(parallel [ @@ -284,11 +290,15 @@ UNSPEC_SYNC_OLD_OP_12)) (clobber (match_scratch:SI 5 "=&d"))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OLD_OP_12 ("and", MIPS_SYNC_OLD_OP_12_XOR); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "and") + (set_attr "sync_insn2" "xor") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_insn1_op2" "4") + (set_attr "sync_newval" "5")]) (define_expand "sync_new_nand<mode>" [(parallel [ @@ -324,24 +334,27 @@ (match_dup 3) (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_NEW_OP_12 ("and", MIPS_SYNC_NEW_OP_12_XOR); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "40")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "and") + (set_attr "sync_insn2" "xor") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_insn1_op2" "4")]) (define_insn "sync_sub<mode>" [(set (match_operand:GPR 0 "memory_operand" "+R") (unspec_volatile:GPR [(minus:GPR (match_dup 0) - (match_operand:GPR 1 "register_operand" "d"))] + (match_operand:GPR 1 "register_operand" "d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OP ("<d>", "<d>subu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "subu") + (set_attr "sync_mem" "0") + (set_attr "sync_insn1_op2" "1")]) (define_insn "sync_old_add<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -352,15 +365,11 @@ (match_operand:GPR 2 "arith_operand" "I,d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_OLD_OP ("<d>", "<d>addiu"); - else - loop = MIPS_SYNC_OLD_OP ("<d>", "<d>addu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "addiu,addu") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_old_sub<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d") @@ -371,11 +380,11 @@ (match_operand:GPR 2 "register_operand" "d"))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_OLD_OP ("<d>", "<d>subu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "subu") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_new_add<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -386,15 +395,12 @@ [(plus:GPR (match_dup 1) (match_dup 2))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_NEW_OP ("<d>", "<d>addiu"); - else - loop = MIPS_SYNC_NEW_OP ("<d>", "<d>addu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "addiu,addu") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_new_sub<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d") @@ -405,11 +411,12 @@ [(minus:GPR (match_dup 1) (match_dup 2))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" -{ - const char *loop = MIPS_SYNC_NEW_OP ("<d>", "<d>subu"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "subu") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_<optab><mode>" [(set (match_operand:GPR 0 "memory_operand" "+R,R") @@ -418,15 +425,10 @@ (match_dup 0))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_OP ("<d>", "<immediate_insn>"); - else - loop = MIPS_SYNC_OP ("<d>", "<insn>"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<immediate_insn>,<insn>") + (set_attr "sync_mem" "0") + (set_attr "sync_insn1_op2" "1")]) (define_insn "sync_old_<optab><mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -437,15 +439,11 @@ (match_dup 1))] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_OLD_OP ("<d>", "<immediate_insn>"); - else - loop = MIPS_SYNC_OLD_OP ("<d>", "<insn>"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<immediate_insn>,<insn>") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_new_<optab><mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -456,30 +454,23 @@ (match_dup 1))] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_NEW_OP ("<d>", "<immediate_insn>"); - else - loop = MIPS_SYNC_NEW_OP ("<d>", "<insn>"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "28")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "<immediate_insn>,<insn>") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_nand<mode>" [(set (match_operand:GPR 0 "memory_operand" "+R,R") (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_NAND ("<d>", "andi"); - else - loop = MIPS_SYNC_NAND ("<d>", "and"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "32")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "andi,and") + (set_attr "sync_insn2" "not") + (set_attr "sync_mem" "0") + (set_attr "sync_insn1_op2" "1")]) (define_insn "sync_old_nand<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -488,15 +479,12 @@ (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] UNSPEC_SYNC_OLD_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_OLD_NAND ("<d>", "andi"); - else - loop = MIPS_SYNC_OLD_NAND ("<d>", "and"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "32")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "andi,and") + (set_attr "sync_insn2" "not") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_new_nand<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -505,15 +493,13 @@ (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")] UNSPEC_SYNC_NEW_OP))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_NEW_NAND ("<d>", "andi"); - else - loop = MIPS_SYNC_NEW_NAND ("<d>", "and"); - return mips_output_sync_loop (true, loop, operands); -} - [(set_attr "length" "32")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_insn1" "andi,and") + (set_attr "sync_insn2" "not") + (set_attr "sync_oldval" "0") + (set_attr "sync_newval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_insn "sync_lock_test_and_set<mode>" [(set (match_operand:GPR 0 "register_operand" "=&d,&d") @@ -522,15 +508,12 @@ (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")] UNSPEC_SYNC_EXCHANGE))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_EXCHANGE ("<d>", "li"); - else - loop = MIPS_SYNC_EXCHANGE ("<d>", "move"); - return mips_output_sync_loop (false, loop, operands); -} - [(set_attr "length" "24")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_release_barrier" "no") + (set_attr "sync_insn1" "li,move") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + (set_attr "sync_insn1_op2" "2")]) (define_expand "sync_lock_test_and_set<mode>" [(match_operand:SHORT 0 "register_operand") @@ -546,20 +529,20 @@ }) (define_insn "test_and_set_12" - [(set (match_operand:SI 0 "register_operand" "=&d,&d") - (match_operand:SI 1 "memory_operand" "+R,R")) + [(set (match_operand:SI 0 "register_operand" "=&d") + (match_operand:SI 1 "memory_operand" "+R")) (set (match_dup 1) - (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d") - (match_operand:SI 3 "register_operand" "d,d") - (match_operand:SI 4 "arith_operand" "d,J")] + (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d") + (match_operand:SI 4 "arith_operand" "dJ")] UNSPEC_SYNC_EXCHANGE_12))] "GENERATE_LL_SC" -{ - const char *loop; - if (which_alternative == 0) - loop = MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_NONZERO_OP); - else - loop = MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_ZERO_OP); - return mips_output_sync_loop (false, loop, operands); -} - [(set_attr "length" "28,24")]) + { return mips_output_sync_loop (insn, operands); } + [(set_attr "sync_release_barrier" "no") + (set_attr "sync_oldval" "0") + (set_attr "sync_mem" "1") + ;; Unused, but needed to give the number of operands expected by + ;; the expander. + (set_attr "sync_inclusive_mask" "2") + (set_attr "sync_exclusive_mask" "3") + (set_attr "sync_insn1_op2" "4")]) |