/* Instruction scheduling pass. This file contains definitions used internally in the scheduler. Copyright (C) 2006-2018 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 . */ #ifndef GCC_SEL_SCHED_IR_H #define GCC_SEL_SCHED_IR_H /* For state_t. */ /* For reg_note. */ /* tc_t is a short for target context. This is a state of the target backend. */ typedef void *tc_t; /* List data types used for av sets, fences, paths, and boundaries. */ /* Forward declarations for types that are part of some list nodes. */ struct _list_node; /* List backend. */ typedef struct _list_node *_list_t; #define _LIST_NEXT(L) ((L)->next) /* Instruction data that is part of vinsn type. */ struct idata_def; typedef struct idata_def *idata_t; /* A virtual instruction, i.e. an instruction as seen by the scheduler. */ struct vinsn_def; typedef struct vinsn_def *vinsn_t; /* RTX list. This type is the backend for ilist. */ typedef _list_t _xlist_t; #define _XLIST_X(L) ((L)->u.x) #define _XLIST_NEXT(L) (_LIST_NEXT (L)) /* Instruction. */ typedef rtx_insn *insn_t; /* List of insns. */ typedef _list_t ilist_t; #define ILIST_INSN(L) ((L)->u.insn) #define ILIST_NEXT(L) (_LIST_NEXT (L)) /* This lists possible transformations that done locally, i.e. in moveup_expr. */ enum local_trans_type { TRANS_SUBSTITUTION, TRANS_SPECULATION }; /* This struct is used to record the history of expression's transformations. */ struct expr_history_def_1 { /* UID of the insn. */ unsigned uid; /* How the expression looked like. */ vinsn_t old_expr_vinsn; /* How the expression looks after the transformation. */ vinsn_t new_expr_vinsn; /* And its speculative status. */ ds_t spec_ds; /* Type of the transformation. */ enum local_trans_type type; }; typedef struct expr_history_def_1 expr_history_def; /* Expression information. */ struct _expr { /* Insn description. */ vinsn_t vinsn; /* SPEC is the degree of speculativeness. FIXME: now spec is increased when an rhs is moved through a conditional, thus showing only control speculativeness. In the future we'd like to count data spec separately to allow a better control on scheduling. */ int spec; /* Degree of speculativeness measured as probability of executing instruction's original basic block given relative to the current scheduling point. */ int usefulness; /* A priority of this expression. */ int priority; /* A priority adjustment of this expression. */ int priority_adj; /* Number of times the insn was scheduled. */ int sched_times; /* A basic block index this was originated from. Zero when there is more than one originator. */ int orig_bb_index; /* Instruction should be of SPEC_DONE_DS type in order to be moved to this point. */ ds_t spec_done_ds; /* SPEC_TO_CHECK_DS hold speculation types that should be checked (used only during move_op ()). */ ds_t spec_to_check_ds; /* Cycle on which original insn was scheduled. Zero when it has not yet been scheduled or more than one originator. */ int orig_sched_cycle; /* This vector contains the history of insn's transformations. */ vec history_of_changes; /* True (1) when original target (register or memory) of this instruction is available for scheduling, false otherwise. -1 means we're not sure; please run find_used_regs to clarify. */ signed char target_available; /* True when this expression needs a speculation check to be scheduled. This is used during find_used_regs. */ BOOL_BITFIELD needs_spec_check_p : 1; /* True when the expression was substituted. Used for statistical purposes. */ BOOL_BITFIELD was_substituted : 1; /* True when the expression was renamed. */ BOOL_BITFIELD was_renamed : 1; /* True when expression can't be moved. */ BOOL_BITFIELD cant_move : 1; }; typedef struct _expr expr_def; typedef expr_def *expr_t; #define EXPR_VINSN(EXPR) ((EXPR)->vinsn) #define EXPR_INSN_RTX(EXPR) (VINSN_INSN_RTX (EXPR_VINSN (EXPR))) #define EXPR_PATTERN(EXPR) (VINSN_PATTERN (EXPR_VINSN (EXPR))) #define EXPR_LHS(EXPR) (VINSN_LHS (EXPR_VINSN (EXPR))) #define EXPR_RHS(EXPR) (VINSN_RHS (EXPR_VINSN (EXPR))) #define EXPR_TYPE(EXPR) (VINSN_TYPE (EXPR_VINSN (EXPR))) #define EXPR_SEPARABLE_P(EXPR) (VINSN_SEPARABLE_P (EXPR_VINSN (EXPR))) #define EXPR_SPEC(EXPR) ((EXPR)->spec) #define EXPR_USEFULNESS(EXPR) ((EXPR)->usefulness) #define EXPR_PRIORITY(EXPR) ((EXPR)->priority) #define EXPR_PRIORITY_ADJ(EXPR) ((EXPR)->priority_adj) #define EXPR_SCHED_TIMES(EXPR) ((EXPR)->sched_times) #define EXPR_ORIG_BB_INDEX(EXPR) ((EXPR)->orig_bb_index) #define EXPR_ORIG_SCHED_CYCLE(EXPR) ((EXPR)->orig_sched_cycle) #define EXPR_SPEC_DONE_DS(EXPR) ((EXPR)->spec_done_ds) #define EXPR_SPEC_TO_CHECK_DS(EXPR) ((EXPR)->spec_to_check_ds) #define EXPR_HISTORY_OF_CHANGES(EXPR) ((EXPR)->history_of_changes) #define EXPR_TARGET_AVAILABLE(EXPR) ((EXPR)->target_available) #define EXPR_NEEDS_SPEC_CHECK_P(EXPR) ((EXPR)->needs_spec_check_p) #define EXPR_WAS_SUBSTITUTED(EXPR) ((EXPR)->was_substituted) #define EXPR_WAS_RENAMED(EXPR) ((EXPR)->was_renamed) #define EXPR_CANT_MOVE(EXPR) ((EXPR)->cant_move) /* Insn definition for list of original insns in find_used_regs. */ struct _def { insn_t orig_insn; /* FIXME: Get rid of CROSSES_CALL in each def, since if we're moving up rhs from two different places, but only one of the code motion paths crosses a call, we can't use any of the call_used_regs, no matter which path or whether all paths crosses a call. Thus we should move CROSSES_CALL to static params. */ bool crosses_call; }; typedef struct _def *def_t; /* Availability sets are sets of expressions we're scheduling. */ typedef _list_t av_set_t; #define _AV_SET_EXPR(L) (&(L)->u.expr) #define _AV_SET_NEXT(L) (_LIST_NEXT (L)) /* Boundary of the current fence group. */ struct _bnd { /* The actual boundary instruction. */ insn_t to; /* Its path to the fence. */ ilist_t ptr; /* Availability set at the boundary. */ av_set_t av; /* This set moved to the fence. */ av_set_t av1; /* Deps context at this boundary. As long as we have one boundary per fence, this is just a pointer to the same deps context as in the corresponding fence. */ deps_t dc; }; typedef struct _bnd *bnd_t; #define BND_TO(B) ((B)->to) /* PTR stands not for pointer as you might think, but as a Path To Root of the current instruction group from boundary B. */ #define BND_PTR(B) ((B)->ptr) #define BND_AV(B) ((B)->av) #define BND_AV1(B) ((B)->av1) #define BND_DC(B) ((B)->dc) /* List of boundaries. */ typedef _list_t blist_t; #define BLIST_BND(L) (&(L)->u.bnd) #define BLIST_NEXT(L) (_LIST_NEXT (L)) /* Fence information. A fence represents current scheduling point and also blocks code motion through it when pipelining. */ struct _fence { /* Insn before which we gather an instruction group.*/ insn_t insn; /* Modeled state of the processor pipeline. */ state_t state; /* Current cycle that is being scheduled on this fence. */ int cycle; /* Number of insns that were scheduled on the current cycle. This information has to be local to a fence. */ int cycle_issued_insns; /* At the end of fill_insns () this field holds the list of the instructions that are inner boundaries of the scheduled parallel group. */ ilist_t bnds; /* Deps context at this fence. It is used to model dependencies at the fence so that insn ticks can be properly evaluated. */ deps_t dc; /* Target context at this fence. Used to save and load any local target scheduling information when changing fences. */ tc_t tc; /* A vector of insns that are scheduled but not yet completed. */ vec *executing_insns; /* A vector indexed by UIDs that caches the earliest cycle on which an insn can be scheduled on this fence. */ int *ready_ticks; /* Its size. */ int ready_ticks_size; /* Insn, which has been scheduled last on this fence. */ rtx_insn *last_scheduled_insn; /* The last value of can_issue_more variable on this fence. */ int issue_more; /* If non-NULL force the next scheduled insn to be SCHED_NEXT. */ rtx_insn *sched_next; /* True if fill_insns processed this fence. */ BOOL_BITFIELD processed_p : 1; /* True if fill_insns actually scheduled something on this fence. */ BOOL_BITFIELD scheduled_p : 1; /* True when the next insn scheduled here would start a cycle. */ BOOL_BITFIELD starts_cycle_p : 1; /* True when the next insn scheduled here would be scheduled after a stall. */ BOOL_BITFIELD after_stall_p : 1; }; typedef struct _fence *fence_t; #define FENCE_INSN(F) ((F)->insn) #define FENCE_STATE(F) ((F)->state) #define FENCE_BNDS(F) ((F)->bnds) #define FENCE_PROCESSED_P(F) ((F)->processed_p) #define FENCE_SCHEDULED_P(F) ((F)->scheduled_p) #define FENCE_ISSUED_INSNS(F) ((F)->cycle_issued_insns) #define FENCE_CYCLE(F) ((F)->cycle) #define FENCE_STARTS_CYCLE_P(F) ((F)->starts_cycle_p) #define FENCE_AFTER_STALL_P(F) ((F)->after_stall_p) #define FENCE_DC(F) ((F)->dc) #define FENCE_TC(F) ((F)->tc) #define FENCE_LAST_SCHEDULED_INSN(F) ((F)->last_scheduled_insn) #define FENCE_ISSUE_MORE(F) ((F)->issue_more) #define FENCE_EXECUTING_INSNS(F) ((F)->executing_insns) #define FENCE_READY_TICKS(F) ((F)->ready_ticks) #define FENCE_READY_TICKS_SIZE(F) ((F)->ready_ticks_size) #define FENCE_SCHED_NEXT(F) ((F)->sched_next) /* List of fences. */ typedef _list_t flist_t; #define FLIST_FENCE(L) (&(L)->u.fence) #define FLIST_NEXT(L) (_LIST_NEXT (L)) /* List of fences with pointer to the tail node. */ struct flist_tail_def { flist_t head; flist_t *tailp; }; typedef struct flist_tail_def *flist_tail_t; #define FLIST_TAIL_HEAD(L) ((L)->head) #define FLIST_TAIL_TAILP(L) ((L)->tailp) /* List node information. A list node can be any of the types above. */ struct _list_node { _list_t next; union { rtx x; insn_t insn; struct _bnd bnd; expr_def expr; struct _fence fence; struct _def def; void *data; } u; };