/* Scheduler hooks for IA-32 which implement atom+ specific logic. Copyright (C) 1988-2022 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #define IN_TARGET_CODE 1 #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "rtl.h" #include "tree.h" #include "cfghooks.h" #include "tm_p.h" #include "insn-config.h" #include "insn-attr.h" #include "recog.h" #include "target.h" #include "rtl-iter.h" #include "regset.h" #include "sched-int.h" /* Try to reorder ready list to take advantage of Atom pipelined IMUL execution. It is applied if (1) IMUL instruction is on the top of list; (2) There exists the only producer of independent IMUL instruction in ready list. Return index of IMUL producer if it was found and -1 otherwise. */ static int do_reorder_for_imul (rtx_insn **ready, int n_ready) { rtx_insn *insn; rtx set, insn1, insn2; sd_iterator_def sd_it; dep_t dep; int index = -1; int i; if (!TARGET_CPU_P (BONNELL)) return index; /* Check that IMUL instruction is on the top of ready list. */ insn = ready[n_ready - 1]; set = single_set (insn); if (!set) return index; if (!(GET_CODE (SET_SRC (set)) == MULT && GET_MODE (SET_SRC (set)) == SImode)) return index; /* Search for producer of independent IMUL instruction. */ for (i = n_ready - 2; i >= 0; i--) { insn = ready[i]; if (!NONDEBUG_INSN_P (insn)) continue; /* Skip IMUL instruction. */ insn2 = PATTERN (insn); if (GET_CODE (insn2) == PARALLEL) insn2 = XVECEXP (insn2, 0, 0); if (GET_CODE (insn2) == SET && GET_CODE (SET_SRC (insn2)) == MULT && GET_MODE (SET_SRC (insn2)) == SImode) continue; FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep) { rtx con; con = DEP_CON (dep); if (!NONDEBUG_INSN_P (con)) continue; insn1 = PATTERN (con); if (GET_CODE (insn1) == PARALLEL) insn1 = XVECEXP (insn1, 0, 0); if (GET_CODE (insn1) == SET && GET_CODE (SET_SRC (insn1)) == MULT && GET_MODE (SET_SRC (insn1)) == SImode) { sd_iterator_def sd_it1; dep_t dep1; /* Check if there is no other dependee for IMUL. */ index = i; FOR_EACH_DEP (con, SD_LIST_BACK, sd_it1, dep1) { rtx pro; pro = DEP_PRO (dep1); if (!NONDEBUG_INSN_P (pro)) continue; if (pro != insn) index = -1; } if (index >= 0) break; } } if (index >= 0) break; } return index; } /* Try to find the best candidate on the top of ready list if two insns have the same priority - candidate is best if its dependees were scheduled earlier. Applied for Silvermont only. Return true if top 2 insns must be interchanged. */ static bool swap_top_of_ready_list (rtx_insn **ready, int n_ready) { rtx_insn *top = ready[n_ready - 1]; rtx_insn *next = ready[n_ready - 2]; rtx set; sd_iterator_def sd_it; dep_t dep; int clock1 = -1; int clock2 = -1; #define INSN_TICK(INSN) (HID (INSN)->tick) if (!TARGET_CPU_P (SILVERMONT) && !TARGET_CPU_P (INTEL)) return false; if (!NONDEBUG_INSN_P (top)) return false; if (!NONJUMP_INSN_P (top)) return false; if (!NONDEBUG_INSN_P (next)) return false; if (!NONJUMP_INSN_P (next)) return false; set = single_set (top); if (!set) return false; set = single_set (next); if (!set) return false; if (INSN_PRIORITY_KNOWN (top) && INSN_PRIORITY_KNOWN (next)) { if (INSN_PRIORITY (top) != INSN_PRIORITY (next)) return false; /* Determine winner more precise. */ FOR_EACH_DEP (top, SD_LIST_RES_BACK, sd_it, dep) { rtx pro; pro = DEP_PRO (dep); if (!NONDEBUG_INSN_P (pro)) continue; if (INSN_TICK (pro) > clock1) clock1 = INSN_TICK (pro); } FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep) { rtx pro; pro = DEP_PRO (dep); if (!NONDEBUG_INSN_P (pro)) continue; if (INSN_TICK (pro) > clock2) clock2 = INSN_TICK (pro); } if (clock1 == clock2) { /* Determine winner - load must win. */ enum attr_memory memory1, memory2; memory1 = get_attr_memory (top); memory2 = get_attr_memory (next); if (memory2 == MEMORY_LOAD && memory1 != MEMORY_LOAD) return true; } return (bool) (clock2 < clock1); } return false; #undef INSN_TICK } /* Perform possible reodering of ready list for Atom/Silvermont only. Return issue rate. */ int ix86_atom_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready, int *pn_ready, int clock_var) { int issue_rate = -1; int n_ready = *pn_ready; int i; rtx_insn *insn; int index = -1; /* Set up issue rate. */ issue_rate = ix86_issue_rate (); /* Do reodering for BONNELL/SILVERMONT only. */ if (!TARGET_CPU_P (BONNELL) && !TARGET_CPU_P (SILVERMONT) && !TARGET_CPU_P (INTEL)) return issue_rate; /* Nothing to do if ready list contains only 1 instruction. */ if (n_ready <= 1) return issue_rate; /* Do reodering for post-reload scheduler only. */ if (!reload_completed) return issue_rate; if ((index = do_reorder_for_imul (ready, n_ready)) >= 0) { if (sched_verbose > 1) fprintf (dump, ";;\tatom sched_reorder: put %d insn on top\n", INSN_UID (ready[index])); /* Put IMUL producer (ready[index]) at the top of ready list. */ insn = ready[index]; for (i = index; i < n_ready - 1; i++) ready[i] = ready[i + 1]; ready[n_ready - 1] = insn; return issue_rate; } /* Skip selective scheduling since HID is not populated in it. */ if (clock_var != 0 && !sel_sched_p () && swap_top_of_ready_list (ready, n_ready)) { if (sched_verbose > 1) fprintf (dump, ";;\tslm sched_reorder: swap %d and %d insns\n", INSN_UID (ready[n_ready - 1]), INSN_UID (ready[n_ready - 2])); /* Swap 2 top elements of ready list. */ insn = ready[n_ready - 1]; ready[n_ready - 1] = ready[n_ready - 2]; ready[n_ready - 2] = insn; } return issue_rate; }