const char * cgen_insn_name (SIM_CPU *cpu, int i) { return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i))); }
void md_assemble (char * str) { static long delayed_load_register = 0; static long prev_delayed_load_register = 0; static int last_insn_had_delay_slot = 0; static int last_insn_in_noncond_delay_slot = 0; static int last_insn_has_load_delay = 0; static int last_insn_was_memory_access = 0; static int last_insn_was_io_insn = 0; static int last_insn_was_arithmetic_or_logic = 0; static int last_insn_was_branch_insn = 0; static int last_insn_was_conditional_branch_insn = 0; mt_insn insn; char * errmsg; /* Initialize GAS's cgen interface for a new instruction. */ gas_cgen_init_parse (); insn.insn = mt_cgen_assemble_insn (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); if (!insn.insn) { as_bad ("%s", errmsg); return; } /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); /* Handle Scheduling Restrictions. */ if (!no_scheduling_restrictions) { /* Detect consecutive Memory Accesses. */ if (last_insn_was_memory_access && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS) && mt_mach == ms1_64_001) as_warn (_("instruction %s may not follow another memory access instruction."), CGEN_INSN_NAME (insn.insn)); /* Detect consecutive I/O Instructions. */ else if (last_insn_was_io_insn && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN)) as_warn (_("instruction %s may not follow another I/O instruction."), CGEN_INSN_NAME (insn.insn)); /* Detect consecutive branch instructions. */ else if (last_insn_was_branch_insn && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)) as_warn (_("%s may not occupy the delay slot of another branch insn."), CGEN_INSN_NAME (insn.insn)); /* Detect data dependencies on delayed loads: memory and input insns. */ if (last_insn_has_load_delay && delayed_load_register) { if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) as_warn (_("operand references R%ld of previous load."), insn.fields.f_sr1); if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register) as_warn (_("operand references R%ld of previous load."), insn.fields.f_sr2); } /* Detect JAL/RETI hazard */ if (mt_mach == ms2 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD)) { if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register)) as_warn (_("operand references R%ld of previous instruction."), delayed_load_register); else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == prev_delayed_load_register) || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == prev_delayed_load_register)) as_warn (_("operand references R%ld of instruction before previous."), prev_delayed_load_register); } /* Detect data dependency between conditional branch instruction and an immediately preceding arithmetic or logical instruction. */ if (last_insn_was_arithmetic_or_logic && !last_insn_in_noncond_delay_slot && (delayed_load_register != 0) && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) && mt_arch == ms1_64_001) { if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), insn.fields.f_sr1); if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register) as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), insn.fields.f_sr2); } } /* Keep track of details of this insn for processing next insn. */ last_insn_in_noncond_delay_slot = last_insn_was_branch_insn && !last_insn_was_conditional_branch_insn; last_insn_had_delay_slot = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); (void) last_insn_had_delay_slot; last_insn_has_load_delay = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY); last_insn_was_memory_access = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS); last_insn_was_io_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN); last_insn_was_arithmetic_or_logic = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN); last_insn_was_branch_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN); last_insn_was_conditional_branch_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2); prev_delayed_load_register = delayed_load_register; if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR)) delayed_load_register = insn.fields.f_dr; else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR)) delayed_load_register = insn.fields.f_drrr; else /* Insns has no destination register. */ delayed_load_register = 0; /* Generate dwarf2 line numbers. */ dwarf2_emit_insn (4); }