#ifndef LINEARIZE_H #define LINEARIZE_H #include "lib.h" #include "allocate.h" #include "token.h" #include "opcode.h" #include "parse.h" #include "symbol.h" #include "ptrmap.h" struct instruction; struct pseudo_user { struct instruction *insn; pseudo_t *userp; }; DECLARE_ALLOCATOR(pseudo_user); DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user); DECLARE_PTRMAP(phi_map, struct symbol *, struct instruction *); enum pseudo_type { PSEUDO_VOID, PSEUDO_UNDEF, PSEUDO_PHI, PSEUDO_REG, PSEUDO_ARG, PSEUDO_SYM, PSEUDO_VAL, }; struct pseudo { int nr; enum pseudo_type type; struct pseudo_user_list *users; struct ident *ident; union { struct symbol *sym; struct instruction *def; long long value; }; void *priv; }; extern struct pseudo void_pseudo; #define VOID (&void_pseudo) static inline bool is_zero(pseudo_t pseudo) { return pseudo->type == PSEUDO_VAL && pseudo->value == 0; } static inline bool is_nonzero(pseudo_t pseudo) { return pseudo->type == PSEUDO_VAL && pseudo->value != 0; } static inline bool is_positive(pseudo_t pseudo, unsigned size) { return pseudo->type == PSEUDO_VAL && !(pseudo->value & sign_bit(size)); } struct multijmp { struct basic_block *target; long long begin, end; }; struct asm_constraint { pseudo_t pseudo; const char *constraint; const struct ident *ident; unsigned int is_memory:1; }; DECLARE_ALLOCATOR(asm_constraint); DECLARE_PTR_LIST(asm_constraint_list, struct asm_constraint); struct asm_rules { struct asm_constraint_list *inputs; struct asm_constraint_list *outputs; struct asm_constraint_list *clobbers; }; DECLARE_ALLOCATOR(asm_rules); struct instruction { unsigned opcode:7, tainted:1, size:24; struct basic_block *bb; struct position pos; struct symbol *type; pseudo_t target; union { struct /* entrypoint */ { struct pseudo_list *arg_list; }; struct /* branch */ { pseudo_t cond; struct basic_block *bb_true, *bb_false; }; struct /* switch */ { pseudo_t _cond; struct multijmp_list *multijmp_list; }; struct /* phi_node */ { pseudo_t phi_var; // used for SSA conversion struct pseudo_list *phi_list; unsigned int used:1; }; struct /* phi source */ { pseudo_t phi_src; struct instruction *phi_node; }; struct /* unops */ { pseudo_t src; unsigned from; /* slice */ struct symbol *orig_type; /* casts */ }; struct /* memops */ { pseudo_t addr; /* alias .src */ long long offset; unsigned int is_volatile:1; }; struct /* binops and sel */ { pseudo_t src1, src2, src3; }; struct /* compare */ { pseudo_t _src1, _src2; // alias .src[12] struct symbol *itype; // input operands' type }; struct /* setval */ { struct expression *val; }; struct /* setfval */ { long double fvalue; }; struct /* call */ { pseudo_t func; struct pseudo_list *arguments; struct symbol_list *fntypes; }; struct /* context */ { int increment; int check; struct expression *context_expr; }; struct /* asm */ { const char *string; struct asm_rules *asm_rules; unsigned int clobber_memory:1; unsigned int output_memory:1; }; }; }; struct basic_block_list; struct instruction_list; struct basic_block { struct position pos; unsigned long generation; struct entrypoint *ep; struct basic_block_list *parents; /* sources */ struct basic_block_list *children; /* destinations */ struct instruction_list *insns; /* Linear list of instructions */ struct basic_block *idom; /* link to the immediate dominator */ unsigned int nr; /* unique id for label's names */ int dom_level; /* level in the dominance tree */ struct basic_block_list *doms; /* list of BB idominated by this one */ struct pseudo_list *needs, *defines; union { struct phi_map *phi_map;/* needed during SSA conversion */ int postorder_nr; /* postorder number */ int context; /* needed during context checking */ void *priv; }; }; // // return the opcode of the instruction defining ``SRC`` if existing // and OP_BADOP if not. It also assigns the defining instruction // to ``DEF``. #define DEF_OPCODE(DEF, SRC) \ (((SRC)->type == PSEUDO_REG && (DEF = (SRC)->def)) ? DEF->opcode : OP_BADOP) static inline void add_bb(struct basic_block_list **list, struct basic_block *bb) { add_ptr_list(list, bb); } static inline void add_instruction(struct instruction_list **list, struct instruction *insn) { add_ptr_list(list, insn); } static inline void insert_last_instruction(struct basic_block *bb, struct instruction *insn) { struct instruction *last = delete_last_instruction(&bb->insns); add_instruction(&bb->insns, insn); add_instruction(&bb->insns, last); insn->bb = bb; } static inline void add_multijmp(struct multijmp_list **list, struct multijmp *multijmp) { add_ptr_list(list, multijmp); } static inline pseudo_t *add_pseudo(struct pseudo_list **list, pseudo_t pseudo) { return add_ptr_list(list, pseudo); } static inline int remove_pseudo(struct pseudo_list **list, pseudo_t pseudo) { return delete_ptr_list_entry((struct ptr_list **)list, pseudo, 0) != 0; } static inline int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo) { return lookup_ptr_list_entry((struct ptr_list *)list, pseudo); } static inline int bb_terminated(struct basic_block *bb) { struct instruction *insn; if (!bb) return 0; insn = last_instruction(bb->insns); return insn && insn->opcode >= OP_TERMINATOR && insn->opcode <= OP_TERMINATOR_END; } static inline int bb_reachable(struct basic_block *bb) { return bb != NULL; } static inline int lookup_bb(struct basic_block_list *list, struct basic_block *bb) { return lookup_ptr_list_entry((struct ptr_list *)list, bb); } static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list) { add_ptr_list(list, user); } static inline int has_use_list(pseudo_t p) { return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_UNDEF && p->type != PSEUDO_VAL); } static inline bool has_definition(pseudo_t p) { return p->type == PSEUDO_REG || p->type == PSEUDO_PHI; } static inline int pseudo_user_list_size(struct pseudo_user_list *list) { return ptr_list_size((struct ptr_list *)list); } static inline bool pseudo_user_list_empty(struct pseudo_user_list *list) { return ptr_list_empty((struct ptr_list *)list); } static inline int has_users(pseudo_t p) { return !pseudo_user_list_empty(p->users); } static inline bool one_use(pseudo_t p) { return !ptr_list_multiple((struct ptr_list *)(p->users)); } static inline int nbr_users(pseudo_t p) { return pseudo_user_list_size(p->users); } static inline struct pseudo_user *alloc_pseudo_user(struct instruction *insn, pseudo_t *pp) { struct pseudo_user *user = __alloc_pseudo_user(0); user->userp = pp; user->insn = insn; return user; } static inline void use_pseudo(struct instruction *insn, pseudo_t p, pseudo_t *pp) { *pp = p; if (has_use_list(p)) add_pseudo_user_ptr(alloc_pseudo_user(insn, pp), &p->users); } static inline void link_phi(struct instruction *node, pseudo_t phi) { use_pseudo(node, phi, add_pseudo(&node->phi_list, phi)); phi->def->phi_node = node; } static inline void remove_bb_from_list(struct basic_block_list **list, struct basic_block *entry, int count) { delete_ptr_list_entry((struct ptr_list **)list, entry, count); } static inline void replace_bb_in_list(struct basic_block_list **list, struct basic_block *old, struct basic_block *new, int count) { replace_ptr_list_entry((struct ptr_list **)list, old, new, count); } struct entrypoint { struct symbol *name; struct symbol_list *syms; struct pseudo_list *accesses; struct basic_block_list *bbs; struct basic_block *active; struct instruction *entry; unsigned int dom_levels; /* max levels in the dom tree */ }; extern void insert_select(struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t if_true, pseudo_t if_false); struct instruction *alloc_phisrc(pseudo_t pseudo, struct symbol *type); struct instruction *alloc_phi_node(struct basic_block *bb, struct symbol *type, struct ident *ident); struct instruction *insert_phi_node(struct basic_block *bb, struct symbol *var); void add_phi_node(struct basic_block *bb, struct instruction *phi_node); pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, struct symbol *type); pseudo_t alloc_pseudo(struct instruction *def); pseudo_t value_pseudo(long long val); pseudo_t undef_pseudo(void); struct entrypoint *linearize_symbol(struct symbol *sym); int unssa(struct entrypoint *ep); void show_entry(struct entrypoint *ep); void show_insn_entry(struct instruction *insn); const char *show_pseudo(pseudo_t pseudo); void show_bb(struct basic_block *bb); void show_insn_bb(struct instruction *insn); const char *show_instruction(struct instruction *insn); const char *show_label(struct basic_block *bb); #endif /* LINEARIZE_H */