This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: DFA Instruction Output for VLIW
Dan Towner wrote:
> Vlad,
>
> > You could use dfa pipeline hazard recognizer on final phase (see macro
> > FINAL_PRESCAN_INSN) to find start of a new VLIW insn and get an
> > execution unit used by the insn. In this case you should describe such
> > units as (define_query_cpu_unit).
>
> How do I query an instruction rtx to find out which EU it uses? I've
> looked through the documentation, but can't find a description anywhere,
> nor can I find another target which uses the query operation either.
>
> Thanks,
>
> Dan.
The interfaces of all gcc utilities (genattrtab, genattr, gen...) are not
described in the documentation. Now no one port uses queried units. It was
used in an experimental patch for ia64 port. I am still going to use it for
ia64 port in near future.
The first of all you should define macro
#define CPU_UNITS_QUERY 1
in <port>.h file to switch on code for querying units.
After that you should get an internal code of queried unit with the aid of
function
int get_cpu_unit_code (char *unit_name);
To figure out that the unit is reserved in given state, you should use the
function
int cpu_unit_reservation_p (void *state, int code);
The function returns nonzero if the unit with given code is reserved in given
state.
I put the part of the old patch for ia64 as an example.
Vlad
+ static int ia64_stop_bit_p;
+
+ /* The following variable is used to output modifiers of assembler
+ code of the current output insn. */
+ static rtx *ia64_insn_operands;
+
+ static char *ia64_template = NULL;
+
+ /* Assign a unique number to each insn that is output.
+ This can be used to generate unique local labels. */
+ static int insn_counter = 0;
+
+ /* The following function is used to add stop bits to insns if it is
+ necessary. */
+ const char *
+ ia64_asm_output_opcode (f, ptr)
+ FILE *f;
+ const char *ptr;
+ {
+ int c;
+ rtx op;
+
+ #ifdef CLASSIC
+ if (optimize == 0 || !flag_schedule_insns_after_reload)
+ #endif
+ return ptr;
+ #if OLD_PIPELINE_INTERFACE
+ if (!USE_AUTOMATON_PIPELINE_INTERFACE)
+ return ptr;
+ #endif
+ insn_counter++;
+ if (ia64_template != NULL)
+ {
+ fprintf (f, ".%s\n\t", ia64_template);
+ ia64_template = NULL;
+ }
+ for (; *ptr;)
+ {
+ c = *ptr++;
+ if (c == '%')
+ {
+ int code;
+
+ code = (*ptr >= '0' && *ptr <= '9' ? 0: *ptr++);
+ c = (*ptr >= '0' && *ptr <= '9' ? atoi (ptr) : -1);
+ op = (c < 0 ? NULL_RTX : ia64_insn_operands [c]);
+ if (code == '%')
+ fputc ('%', f);
+ else if (code == '=')
+ fprintf (f, "%d", insn_counter);
+ else if (code == 'l')
+ output_asm_label (op);
+ else if (code == 'a')
+ output_address (op);
+ else if (code == 'c')
+ {
+ if (CONSTANT_ADDRESS_P (op))
+ output_addr_const (f, op);
+ else
+ ia64_print_operand (f, op, 'c');
+ }
+ else if (code == 'n')
+ {
+ if (GET_CODE (op) == CONST_INT)
+ fprintf (f, HOST_WIDE_INT_PRINT_DEC, - INTVAL (op));
+ else
+ {
+ putc ('-', f);
+ output_addr_const (f, op);
+ }
+ }
+ else
+ ia64_print_operand (f, op, code);
+ while ((c = *ptr) >= '0' && c <= '9')
+ ptr++;
+ }
+ else
+ fputc (c, f);
+ }
+
+ if (ia64_stop_bit_p)
+ fprintf (f, "\n\t;;");
+
+ return ptr;
+ }
+
+ static state_t curr_state;
+ static int b0_sm0, b0_sb0, b0_sm1, b0_sm1cont, b0_si1, b0_sl1, b0_sf1, b0_sb1;
+ static int b0_si2, b0_si2cont, b0_sf2, b0_sb2;
+ static int b1_sm0, b1_sb0, b1_sm1, b1_si1, b1_sl1, b1_sf1, b1_sb1;
+ static int b1_si2, b1_sf2, b1_sb2;
+
+ /* The following function sets up the packing bit for the current
+ output insn. Remember that the function is not called for asm
+ insns. */
+
+ void
+ ia64_final_prescan_insn (insn, opvec, noperands)
+ rtx insn;
+ rtx *opvec;
+ int noperands ATTRIBUTE_UNUSED;
+ {
+ RTX_CODE code;
+ rtx curr_insn;
+ static char template [4];
+ size_t size;
+ state_t temp_state;
+ state_t temp_state1;
+ state_t temp_state2;
+ int first_bundle_p;
+ int old_which_alternative;
+ int i;
+
+ #ifdef CLASSIC
+ if (optimize == 0 || !flag_schedule_insns_after_reload)
+ #endif
+ return;
+ #if OLD_PIPELINE_INTERFACE
+ if (!USE_AUTOMATON_PIPELINE_INTERFACE)
+ return;
+ #endif
+ if (curr_state == NULL)
+ {
+ curr_state = xmalloc (state_size ());
+ state_reset (curr_state);
+ b0_sm0 = get_cpu_unit_code ("b0_sm0");
+ b0_sb0 = get_cpu_unit_code ("b0_sb0");
+ b0_sm1 = get_cpu_unit_code ("b0_sm1");
+ b0_sm1cont = get_cpu_unit_code ("b0_sm1cont");
+ b0_si1 = get_cpu_unit_code ("b0_si1");
+ b0_sl1 = get_cpu_unit_code ("b0_sl1");
+ b0_sf1 = get_cpu_unit_code ("b0_sf1");
+ b0_sb1 = get_cpu_unit_code ("b0_sb1");
+ b0_si2 = get_cpu_unit_code ("b0_si2");
+ b0_si2cont = get_cpu_unit_code ("b0_si2cont");
+ b0_sf2 = get_cpu_unit_code ("b0_sf2");
+ b0_sb2 = get_cpu_unit_code ("b0_sb2");
+ b1_sm0 = get_cpu_unit_code ("b1_sm0");
+ b1_sb0 = get_cpu_unit_code ("b1_sb0");
+ b1_sm1 = get_cpu_unit_code ("b1_sm1");
+ b1_si1 = get_cpu_unit_code ("b1_si1");
+ b1_sl1 = get_cpu_unit_code ("b1_sl1");
+ b1_sf1 = get_cpu_unit_code ("b1_sf1");
+ b1_sb1 = get_cpu_unit_code ("b1_sb1");
+ b1_si2 = get_cpu_unit_code ("b1_si2");
+ b1_sf2 = get_cpu_unit_code ("b1_sf2");
+ b1_sb2 = get_cpu_unit_code ("b1_sb2");
+ if (b0_sm0 < 0 || b0_sb0 < 0 || b0_sm1 < 0 || b0_sm1cont < 0
+ || b0_si1 < 0 || b0_sl1 < 0 || b0_sf1 < 0 || b0_sb1 < 0
+ || b0_si2 < 0 || b0_si2cont < 0 || b0_sf2 < 0 || b0_sb2 < 0
+ || b1_sm0 < 0 || b1_sb0 < 0 || b1_sm1 < 0 || b1_si1 < 0
+ || b1_sl1 < 0 || b1_sf1 < 0 || b1_sb1 < 0 || b1_si2 < 0
+ || b1_sf2 < 0 || b1_sb2 < 0)
+ abort ();
+ }
+ ia64_insn_operands = opvec;
+ ia64_stop_bit_p = FALSE;
+ for (curr_insn = insn;;)
+ {
+ curr_insn = NEXT_INSN (curr_insn);
+ if (curr_insn == NULL)
+ {
+ #if 0
+ ia64_stop_bit_p = TRUE;
+ #endif
+ break;
+ }
+ code = GET_CODE (curr_insn);
+ if (GET_RTX_CLASS (code) != 'i' && code != NOTE)
+ {
+ #if 0
+ ia64_stop_bit_p = TRUE;
+ #endif
+ break;
+ }
+ if (GET_RTX_CLASS (code) == 'i'
+ && GET_CODE (PATTERN (curr_insn)) != CLOBBER
+ && GET_CODE (PATTERN (curr_insn)) != USE)
+ {
+ #if 0
+ if (GET_MODE (curr_insn) != 0)
+ ia64_stop_bit_p = TRUE;
+ #endif
+ break;
+ }
+ }
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ abort ();
+ for (i = GET_MODE (insn); i != 0; i--)
+ {
+ #ifdef DFA_SCHEDULER_PRE_CYCLE_INSN
+ state_transition (curr_state, DFA_SCHEDULER_PRE_CYCLE_INSN);
+ #endif
+ state_transition (curr_state, NULL);
+ }
+ size = state_size ();
+ temp_state = alloca (size);
+ memcpy (temp_state, curr_state, size);
+ if (INSN_CODE (insn) < 0)
+ return;
+ if (state_transition (curr_state, insn) != -1)
+ abort ();
+ if (INSN_CODE (insn) == CODE_FOR_insn_group_barrier)
+ return;
+ first_bundle_p = TRUE;
+ if (!cpu_unit_reservation_p (temp_state, b1_sm0)
+ && cpu_unit_reservation_p (curr_state, b1_sm0))
+ {
+ template [0] = 'm';
+ first_bundle_p = FALSE;
+ }
+ else if (!cpu_unit_reservation_p (temp_state, b1_sb0)
+ && cpu_unit_reservation_p (curr_state, b1_sb0))
+ {
+ template [0] = 'b';
+ first_bundle_p = FALSE;
+ }
+ else if (!cpu_unit_reservation_p (temp_state, b0_sm0)
+ && cpu_unit_reservation_p (curr_state, b0_sm0))
+ template [0] = 'm';
+ else if (!cpu_unit_reservation_p (temp_state, b0_sb0)
+ && cpu_unit_reservation_p (curr_state, b0_sb0))
+ template [0] = 'b';
+ else
+ template [0] = '\0';
+ if (template [0] != '\0')
+ {
+ template [1] = template [2] = template [3] = '\0';
+ memcpy (temp_state, curr_state, size);
+ temp_state1 = alloca (size);
+ temp_state2 = alloca (size);
+ old_which_alternative = which_alternative;
+ for (curr_insn = insn;;)
+ {
+ curr_insn = NEXT_INSN (curr_insn);
+ if (curr_insn == NULL
+ || GET_RTX_CLASS (GET_CODE (curr_insn)) != 'i'
+ && GET_CODE (curr_insn) != NOTE)
+ {
+ if (template [0] == 'b')
+ {
+ if (template [1] != '\0')
+ abort ();
+ if (cpu_unit_reservation_p (temp_state, b0_sm0)
+ && cpu_unit_reservation_p (temp_state, b0_sm1))
+ ia64_template = "bbb\n\tnop.b 0\n\tnop.b 0";
+ else
+ /* Only one f insn is possible in the previous template. */
+ ia64_template = "mfb";
+ }
+ else if (template [1] == '\0')
+ ia64_template = "mfb";
+ else if (template [2] != '\0')
+ ia64_template = template;
+ else if (template [1] == 'm')
+ {
+ if (cpu_unit_reservation_p (temp_state, b0_sm1cont))
+ ia64_template = "mmi"; /* it is actually m;mi */
+ else
+ ia64_template = "mmb";
+ }
+ else if (template [1] == 'i')
+ ia64_template = "mib";
+ else if (template [1] == 'l')
+ ia64_template = "mlx";
+ else if (template [1] == 'f')
+ ia64_template = "mfb";
+ else if (template [1] == 'b')
+ {
+ if (template [1] != 'b')
+ abort ();
+ ia64_template = "mfb";
+ }
+ else
+ abort ();
+ break;
+ }
+ if (GET_RTX_CLASS (GET_CODE (curr_insn)) == 'i'
+ && GET_CODE (PATTERN (curr_insn)) != CLOBBER
+ && GET_CODE (PATTERN (curr_insn)) != USE)
+ {
+ memcpy (temp_state2, temp_state, size);
+ for (i = GET_MODE (curr_insn); i != 0; i--)
+ {
+ first_bundle_p = TRUE;
+ #ifdef DFA_SCHEDULER_PRE_CYCLE_INSN
+ state_transition (temp_state, DFA_SCHEDULER_PRE_CYCLE_INSN);
+ #endif
+ state_transition (temp_state, NULL);
+ }
+ memcpy (temp_state1, temp_state, size);
+ if (INSN_CODE (curr_insn) >= 0
+ && state_transition (temp_state, curr_insn) != -1)
+ abort ();
+ if (INSN_CODE (curr_insn) == CODE_FOR_blockage
+ || INSN_CODE (curr_insn) == CODE_FOR_safe_across_calls_normal
+ || INSN_CODE (curr_insn) == CODE_FOR_safe_across_calls_all
+ || INSN_CODE (curr_insn) == CODE_FOR_pred_rel_mutex)
+ continue;
+ if (INSN_CODE (curr_insn) < 0
+ || !cpu_unit_reservation_p (temp_state1, b0_sm0)
+ && cpu_unit_reservation_p (temp_state, b0_sm0)
+ || !cpu_unit_reservation_p (temp_state1, b1_sm0)
+ && cpu_unit_reservation_p (temp_state, b1_sm0)
+ || !cpu_unit_reservation_p (temp_state1, b0_sb0)
+ && cpu_unit_reservation_p (temp_state, b0_sb0)
+ || !cpu_unit_reservation_p (temp_state1, b1_sb0)
+ && cpu_unit_reservation_p (temp_state, b1_sb0))
+ {
+ if (template [0] == 'b')
+ {
+ if (template [1] != '\0')
+ abort ();
+ if (cpu_unit_reservation_p (temp_state, b0_sm0)
+ && cpu_unit_reservation_p (temp_state, b0_sm1))
+ ia64_template = "bbb\n\tnop.b 0\n\tnop.b 0";
+ else
+ /* Only one f insn is possible in the previous
+ template. */
+ ia64_template = "mfb";
+ }
+ else if (template [1] == '\0')
+ ia64_template = "mfb";
+ else if (template [2] == '\0')
+ {
+ if (template [1] == 'm')
+ {
+ if (cpu_unit_reservation_p (temp_state2, b0_sm1cont))
+ ia64_template = "mmi"; /* it is actually m;mi */
+ else
+ ia64_template = "mmb";
+ }
+ else if (template [1] == 'i')
+ ia64_template = "mib";
+ else if (template [1] == 'l')
+ ia64_template = "mlx";
+ else if (template [1] == 'f')
+ ia64_template = "mfb";
+ else
+ {
+ if (template [1] != 'b')
+ abort ();
+ ia64_template = "mfb";
+ }
+ }
+ else
+ ia64_template = template;
+ break;
+ }
+ else if (INSN_CODE (curr_insn) == CODE_FOR_insn_group_barrier)
+ continue;
+ else if (template [1] == '\0')
+ {
+ if (template [0] == 'b')
+ {
+ if ((!first_bundle_p
+ || !cpu_unit_reservation_p (temp_state, b0_sb1))
+ && !cpu_unit_reservation_p (temp_state, b1_sb1))
+ abort ();
+ template [1] = 'b';
+ }
+ else if (first_bundle_p
+ && (cpu_unit_reservation_p (temp_state, b0_sm1)
+ || cpu_unit_reservation_p (temp_state,
+ b0_sm1cont))
+ || cpu_unit_reservation_p (temp_state, b1_sm1))
+ template [1] = 'm';
+ else if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_si1)
+ || cpu_unit_reservation_p (temp_state, b1_si1))
+ template [1] = 'i';
+ else if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sl1)
+ || cpu_unit_reservation_p (temp_state, b1_sl1))
+ template [1] = 'l';
+ else if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sf1)
+ || cpu_unit_reservation_p (temp_state, b1_sf1))
+ template [1] = 'f';
+ else if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sb1)
+ || cpu_unit_reservation_p (temp_state, b1_sb1))
+ template [1] = 'b';
+ else
+ abort ();
+ }
+ else if (template [0] == 'b')
+ {
+ if (template [1] != 'b'
+ || (!first_bundle_p
+ || !cpu_unit_reservation_p (temp_state, b0_sb2))
+ && !cpu_unit_reservation_p (temp_state, b1_sb2))
+ abort ();
+ template [2] = 'b';
+ }
+ else if (template [1] == 'b')
+ {
+ if ((!first_bundle_p
+ || !cpu_unit_reservation_p (temp_state, b0_sb2))
+ && !cpu_unit_reservation_p (temp_state, b1_sb2))
+ abort ();
+ template [2] = 'b';
+ }
+ else if (template [1] == 'm')
+ {
+ if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sb2)
+ || cpu_unit_reservation_p (temp_state, b1_sb2))
+ template [2] = 'b';
+ else if (first_bundle_p
+ && (cpu_unit_reservation_p (temp_state, b0_si2)
+ || cpu_unit_reservation_p (temp_state,
+ b0_si2cont))
+ || cpu_unit_reservation_p (temp_state, b1_si2))
+ template [2] = 'i';
+ else if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sf2)
+ || cpu_unit_reservation_p (temp_state, b1_sf2))
+ template [2] = 'f';
+ else
+ abort ();
+ }
+ else if (template [1] == 'i')
+ {
+ if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sb2)
+ || cpu_unit_reservation_p (temp_state, b1_sb2))
+ template [2] = 'b';
+ else if (first_bundle_p
+ && (cpu_unit_reservation_p (temp_state, b0_si2)
+ || cpu_unit_reservation_p (temp_state,
+ b0_si2cont))
+ || cpu_unit_reservation_p (temp_state, b1_si2))
+ template [2] = 'i';
+ else
+ abort ();
+ }
+ else if (template [1] == 'f')
+ {
+ if (first_bundle_p
+ && cpu_unit_reservation_p (temp_state, b0_sb2)
+ || cpu_unit_reservation_p (temp_state, b1_sb2))
+ template [2] = 'b';
+ else if (first_bundle_p
+ && (cpu_unit_reservation_p (temp_state, b0_si2)
+ || cpu_unit_reservation_p (temp_state,
+ b0_si2cont))
+ || cpu_unit_reservation_p (temp_state, b1_si2))
+ template [2] = 'i';
+ else
+ abort ();
+ }
+ else
+ abort ();
+ }
+ }
+ dfa_insn_code (insn);
+ insn_extract (insn);
+ which_alternative = old_which_alternative;
+ }
+ if (GET_CODE (insn) != JUMP_INSN)
+ for (curr_insn = insn;;)
+ {
+ curr_insn = next_nonnote_insn (curr_insn);
+ if (curr_insn == NULL || GET_RTX_CLASS (GET_CODE (curr_insn)) != 'i'
+ || GET_CODE (PATTERN (curr_insn)) != CLOBBER
+ && GET_CODE (PATTERN (curr_insn)) != USE
+ && INSN_CODE (curr_insn) != CODE_FOR_insn_group_barrier)
+ break;
+ }
+ if (GET_CODE (insn) == JUMP_INSN || curr_insn == NULL
+ || GET_RTX_CLASS (GET_CODE (curr_insn)) != 'i'
+ || GET_CODE (PATTERN (curr_insn)) == ASM_INPUT
+ || asm_noperands (PATTERN (curr_insn)) >= 0)
+ state_reset (curr_state);
}