+ subseg_set (seg, subseg);
+ }
+
+ if (done && debug_sym_link)
+ {
+ expand_debug_syms (debug_sym_link, 1);
+ debug_sym_link = (sym_linkS *) 0;
+ }
+
+ return 1;
+}
+\f
+/* The default target format to use. */
+
+const char *
+m32r_target_format (void)
+{
+#ifdef TE_LINUX
+ if (target_big_endian)
+ return "elf32-m32r-linux";
+ else
+ return "elf32-m32rle-linux";
+#else
+ if (target_big_endian)
+ return "elf32-m32r";
+ else
+ return "elf32-m32rle";
+#endif
+}
+
+void
+md_begin (void)
+{
+ flagword applicable;
+ segT seg;
+ subsegT subseg;
+
+ /* Initialize the `cgen' interface. */
+
+ /* Set the machine number and endian. */
+ gas_cgen_cpu_desc = m32r_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
+ CGEN_CPU_OPEN_ENDIAN,
+ (target_big_endian ?
+ CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE),
+ CGEN_CPU_OPEN_END);
+ m32r_cgen_init_asm (gas_cgen_cpu_desc);
+
+ /* The operand instance table is used during optimization to determine
+ which insns can be executed in parallel. It is also used to give
+ warnings regarding operand interference in parallel insns. */
+ m32r_cgen_init_opinst_table (gas_cgen_cpu_desc);
+
+ /* This is a callback from cgen to gas to parse operands. */
+ cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
+
+ /* Save the current subseg so we can restore it [it's the default one and
+ we don't want the initial section to be .sbss]. */
+ seg = now_seg;
+ subseg = now_subseg;
+
+ /* The sbss section is for local .scomm symbols. */
+ sbss_section = subseg_new (".sbss", 0);
+ seg_info (sbss_section)->bss = 1;
+
+ /* This is copied from perform_an_assembly_pass. */
+ applicable = bfd_applicable_section_flags (stdoutput);
+ bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC);
+
+ subseg_set (seg, subseg);
+
+ /* We must construct a fake section similar to bfd_com_section
+ but with the name .scommon. */
+ scom_section = *bfd_com_section_ptr;
+ scom_section.name = ".scommon";
+ scom_section.output_section = & scom_section;
+ scom_section.symbol = & scom_symbol;
+ scom_section.symbol_ptr_ptr = & scom_section.symbol;
+ scom_symbol = * bfd_com_section_ptr->symbol;
+ scom_symbol.name = ".scommon";
+ scom_symbol.section = & scom_section;
+
+ allow_m32rx (enable_m32rx);
+
+ gas_cgen_initialize_saved_fixups_array ();
+}
+
+#define OPERAND_IS_COND_BIT(operand, indices, index) \
+ ((operand)->hw_type == HW_H_COND \
+ || ((operand)->hw_type == HW_H_PSW) \
+ || ((operand)->hw_type == HW_H_CR \
+ && (indices [index] == 0 || indices [index] == 1)))
+
+/* Returns true if an output of instruction 'a' is referenced by an operand
+ of instruction 'b'. If 'check_outputs' is true then b's outputs are
+ checked, otherwise its inputs are examined. */
+
+static int
+first_writes_to_seconds_operands (m32r_insn *a,
+ m32r_insn *b,
+ const int check_outputs)
+{
+ const CGEN_OPINST *a_operands = CGEN_INSN_OPERANDS (a->insn);
+ const CGEN_OPINST *b_ops = CGEN_INSN_OPERANDS (b->insn);
+ int a_index;
+
+ if (ignore_parallel_conflicts)
+ return 0;
+
+ /* If at least one of the instructions takes no operands, then there is
+ nothing to check. There really are instructions without operands,
+ eg 'nop'. */
+ if (a_operands == NULL || b_ops == NULL)
+ return 0;
+
+ /* Scan the operand list of 'a' looking for an output operand. */
+ for (a_index = 0;
+ a_operands->type != CGEN_OPINST_END;
+ a_index ++, a_operands ++)
+ {
+ if (a_operands->type == CGEN_OPINST_OUTPUT)
+ {
+ int b_index;
+ const CGEN_OPINST *b_operands = b_ops;
+
+ /* Special Case:
+ The Condition bit 'C' is a shadow of the CBR register (control
+ register 1) and also a shadow of bit 31 of the program status
+ word (control register 0). For now this is handled here, rather
+ than by cgen.... */
+
+ if (OPERAND_IS_COND_BIT (a_operands, a->indices, a_index))
+ {
+ /* Scan operand list of 'b' looking for another reference to the
+ condition bit, which goes in the right direction. */
+ for (b_index = 0;
+ b_operands->type != CGEN_OPINST_END;
+ b_index++, b_operands++)
+ {
+ if ((b_operands->type
+ == (check_outputs
+ ? CGEN_OPINST_OUTPUT
+ : CGEN_OPINST_INPUT))
+ && OPERAND_IS_COND_BIT (b_operands, b->indices, b_index))
+ return 1;
+ }
+ }
+ else
+ {
+ /* Scan operand list of 'b' looking for an operand that
+ references the same hardware element, and which goes in the
+ right direction. */
+ for (b_index = 0;
+ b_operands->type != CGEN_OPINST_END;
+ b_index++, b_operands++)
+ {
+ if ((b_operands->type
+ == (check_outputs
+ ? CGEN_OPINST_OUTPUT
+ : CGEN_OPINST_INPUT))
+ && (b_operands->hw_type == a_operands->hw_type)
+ && (a->indices[a_index] == b->indices[b_index]))
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Returns true if the insn can (potentially) alter the program counter. */
+
+static int
+writes_to_pc (m32r_insn *a)
+{
+ if (CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_UNCOND_CTI)
+ || CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_COND_CTI))
+ return 1;
+ return 0;
+}
+
+/* Return NULL if the two 16 bit insns can be executed in parallel.
+ Otherwise return a pointer to an error message explaining why not. */
+
+static const char *
+can_make_parallel (m32r_insn *a, m32r_insn *b)
+{
+ PIPE_ATTR a_pipe;
+ PIPE_ATTR b_pipe;
+
+ /* Make sure the instructions are the right length. */
+ if (CGEN_FIELDS_BITSIZE (&a->fields) != 16
+ || CGEN_FIELDS_BITSIZE (&b->fields) != 16)
+ abort ();
+
+ if (first_writes_to_seconds_operands (a, b, TRUE))
+ return _("instructions write to the same destination register.");
+
+ a_pipe = CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_PIPE);
+ b_pipe = CGEN_INSN_ATTR_VALUE (b->insn, CGEN_INSN_PIPE);
+
+ /* Make sure that the instructions use the correct execution pipelines. */
+ if (a_pipe == PIPE_NONE
+ || b_pipe == PIPE_NONE)
+ return _("Instructions do not use parallel execution pipelines.");
+
+ /* Leave this test for last, since it is the only test that can
+ go away if the instructions are swapped, and we want to make
+ sure that any other errors are detected before this happens. */
+ if (a_pipe == PIPE_S
+ || b_pipe == PIPE_O
+ || (b_pipe == PIPE_O_OS && (enable_m32rx != 2)))
+ return _("Instructions share the same execution pipeline");
+
+ return NULL;
+}
+
+/* Force the top bit of the second 16-bit insn to be set. */
+
+static void
+make_parallel (CGEN_INSN_BYTES_PTR buffer)
+{
+#if CGEN_INT_INSN_P
+ *buffer |= 0x8000;
+#else
+ buffer[CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
+ |= 0x80;
+#endif
+}
+
+/* Same as make_parallel except buffer contains the bytes in target order. */
+
+static void
+target_make_parallel (char *buffer)
+{
+ buffer[CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
+ |= 0x80;
+}
+
+/* Assemble two instructions with an explicit parallel operation (||) or
+ sequential operation (->). */
+
+static void
+assemble_two_insns (char *str1, char *str2, int parallel_p)
+{
+ char *str3;
+ m32r_insn first;
+ m32r_insn second;
+ char *errmsg;
+ char save_str2 = *str2;
+
+ /* Separate the two instructions. */
+ *str2 = 0;
+
+ /* Make sure the two insns begin on a 32 bit boundary.
+ This is also done for the serial case (foo -> bar), relaxing doesn't
+ affect insns written like this.
+ Note that we must always do this as we can't assume anything about
+ whether we're currently on a 32 bit boundary or not. Relaxing may
+ change this. */
+ fill_insn (0);
+
+ first.debug_sym_link = debug_sym_link;
+ debug_sym_link = (sym_linkS *) 0;
+
+ /* Parse the first instruction. */
+ if (! (first.insn = m32r_cgen_assemble_insn
+ (gas_cgen_cpu_desc, str1, & first.fields, first.buffer, & errmsg)))
+ {
+ as_bad ("%s", errmsg);
+ return;
+ }
+
+ /* Check it. */
+ if (CGEN_FIELDS_BITSIZE (&first.fields) != 16)
+ {
+ /* xgettext:c-format */
+ as_bad (_("not a 16 bit instruction '%s'"), str1);
+ return;
+ }
+#ifdef E_M32R2_ARCH
+ else if ((enable_m32rx == 1)
+ /* FIXME: Need standard macro to perform this test. */
+ && ((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
+ & (1 << MACH_M32R2))
+ && !((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
+ & (1 << MACH_M32RX)))))
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' is for the M32R2 only"), str1);
+ return;
+ }
+ else if ((! enable_special
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL))
+ || (! enable_special_m32r
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL_M32R)))
+#else
+ else if (! enable_special
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL))
+#endif
+ {
+ /* xgettext:c-format */
+ as_bad (_("unknown instruction '%s'"), str1);
+ return;
+ }
+ else if (! enable_m32rx
+ /* FIXME: Need standard macro to perform this test. */
+ && (CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
+ == (1 << MACH_M32RX)))
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' is for the M32RX only"), str1);
+ return;
+ }
+
+ /* Check to see if this is an allowable parallel insn. */
+ if (parallel_p
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_PIPE) == PIPE_NONE)
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' cannot be executed in parallel."), str1);
+ return;
+ }
+
+ /* Restore the original assembly text, just in case it is needed. */
+ *str2 = save_str2;
+
+ /* Save the original string pointer. */
+ str3 = str1;
+
+ /* Advanced past the parsed string. */
+ str1 = str2 + 2;
+
+ /* Remember the entire string in case it is needed for error
+ messages. */
+ str2 = str3;
+
+ /* Convert the opcode to lower case. */
+ {
+ char *s2 = str1;
+
+ while (ISSPACE (*s2++))
+ continue;
+
+ --s2;
+
+ while (ISALNUM (*s2))
+ {
+ *s2 = TOLOWER (*s2);
+ s2++;
+ }
+ }
+
+ /* Preserve any fixups that have been generated and reset the list
+ to empty. */
+ gas_cgen_save_fixups (0);
+
+ /* Get the indices of the operands of the instruction. */
+ /* FIXME: CGEN_FIELDS is already recorded, but relying on that fact
+ doesn't seem right. Perhaps allow passing fields like we do insn. */
+ /* FIXME: ALIAS insns do not have operands, so we use this function
+ to find the equivalent insn and overwrite the value stored in our
+ structure. We still need the original insn, however, since this
+ may have certain attributes that are not present in the unaliased
+ version (eg relaxability). When aliases behave differently this
+ may have to change. */
+ first.orig_insn = first.insn;
+ {
+ CGEN_FIELDS tmp_fields;
+ first.insn = cgen_lookup_get_insn_operands
+ (gas_cgen_cpu_desc, NULL, INSN_VALUE (first.buffer), NULL, 16,
+ first.indices, &tmp_fields);
+ }
+
+ if (first.insn == NULL)
+ as_fatal (_("internal error: lookup/get operands failed"));
+
+ second.debug_sym_link = NULL;
+
+ /* Parse the second instruction. */
+ if (! (second.insn = m32r_cgen_assemble_insn
+ (gas_cgen_cpu_desc, str1, & second.fields, second.buffer, & errmsg)))
+ {
+ as_bad ("%s", errmsg);
+ return;
+ }
+
+ /* Check it. */
+ if (CGEN_FIELDS_BITSIZE (&second.fields) != 16)
+ {
+ /* xgettext:c-format */
+ as_bad (_("not a 16 bit instruction '%s'"), str1);
+ return;
+ }
+#ifdef E_M32R2_ARCH
+ else if ((enable_m32rx == 1)
+ /* FIXME: Need standard macro to perform this test. */
+ && ((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
+ & (1 << MACH_M32R2))
+ && !((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
+ & (1 << MACH_M32RX)))))
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' is for the M32R2 only"), str1);
+ return;
+ }
+ else if ((! enable_special
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
+ || (! enable_special_m32r
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL_M32R)))
+#else
+ else if (! enable_special
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
+#endif
+ {
+ /* xgettext:c-format */
+ as_bad (_("unknown instruction '%s'"), str1);
+ return;
+ }
+ else if (! enable_m32rx
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' is for the M32RX only"), str1);
+ return;
+ }
+
+ /* Check to see if this is an allowable parallel insn. */
+ if (parallel_p
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_PIPE) == PIPE_NONE)
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' cannot be executed in parallel."), str1);
+ return;