1 #ifndef LINEARIZE_H 2 #define LINEARIZE_H 3 4 #include "lib.h" 5 #include "allocate.h" 6 #include "token.h" 7 #include "parse.h" 8 #include "symbol.h" 9 10 struct instruction; 11 DECLARE_PTR_LIST(pseudo_ptr_list, pseudo_t); 12 13 struct pseudo_user { 14 struct instruction *insn; 15 pseudo_t *userp; 16 }; 17 18 DECLARE_ALLOCATOR(pseudo_user); 19 DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user); 20 21 22 enum pseudo_type { 23 PSEUDO_VOID, 24 PSEUDO_REG, 25 PSEUDO_SYM, 26 PSEUDO_VAL, 27 PSEUDO_ARG, 28 PSEUDO_PHI, 29 }; 30 31 struct pseudo { 32 int nr; 33 int size:16; /* OP_SETVAL only */ 34 enum pseudo_type type:8; 35 struct pseudo_user_list *users; 36 struct ident *ident; 37 union { 38 struct symbol *sym; 39 struct instruction *def; 40 long long value; 41 }; 42 void *priv; 43 }; 44 45 extern struct pseudo void_pseudo; 46 47 #define VOID (&void_pseudo) 48 49 struct multijmp { 50 struct basic_block *target; 51 int begin, end; 52 }; 53 54 struct asm_constraint { 55 pseudo_t pseudo; 56 const char *constraint; 57 const struct ident *ident; 58 }; 59 60 DECLARE_ALLOCATOR(asm_constraint); 61 DECLARE_PTR_LIST(asm_constraint_list, struct asm_constraint); 62 63 struct asm_rules { 64 struct asm_constraint_list *inputs; 65 struct asm_constraint_list *outputs; 66 struct asm_constraint_list *clobbers; 67 }; 68 69 DECLARE_ALLOCATOR(asm_rules); 70 71 struct instruction { 72 unsigned opcode:8, 73 size:24; 74 struct basic_block *bb; 75 struct position pos; 76 struct symbol *type; 77 union { 78 pseudo_t target; 79 pseudo_t cond; /* for branch and switch */ 80 }; 81 union { 82 struct /* entrypoint */ { 83 struct pseudo_list *arg_list; 84 }; 85 struct /* branch */ { 86 struct basic_block *bb_true, *bb_false; 87 }; 88 struct /* switch */ { 89 struct multijmp_list *multijmp_list; 90 }; 91 struct /* phi_node */ { 92 struct pseudo_list *phi_list; 93 }; 94 struct /* phi source */ { 95 pseudo_t phi_src; 96 struct instruction_list *phi_users; 97 }; 98 struct /* unops */ { 99 pseudo_t src; 100 struct symbol *orig_type; /* casts */ 101 unsigned int offset; /* memops */ 102 }; 103 struct /* binops and sel */ { 104 pseudo_t src1, src2, src3; 105 }; 106 struct /* slice */ { 107 pseudo_t base; 108 unsigned from, len; 109 }; 110 struct /* setval */ { 111 pseudo_t symbol; /* Subtle: same offset as "src" !! */ 112 struct expression *val; 113 }; 114 struct /* call */ { 115 pseudo_t func; 116 struct pseudo_list *arguments; 117 struct symbol *fntype; 118 }; 119 struct /* context */ { 120 int increment; 121 int check; 122 struct expression *context_expr; 123 }; 124 struct /* asm */ { 125 const char *string; 126 struct asm_rules *asm_rules; 127 }; 128 }; 129 }; 130 131 enum opcode { 132 OP_BADOP, 133 134 /* Entry */ 135 OP_ENTRY, 136 137 /* Terminator */ 138 OP_TERMINATOR, 139 OP_RET = OP_TERMINATOR, 140 OP_BR, 141 OP_CBR, 142 OP_SWITCH, 143 OP_INVOKE, 144 OP_COMPUTEDGOTO, 145 OP_UNWIND, 146 OP_TERMINATOR_END = OP_UNWIND, 147 148 /* Binary */ 149 OP_BINARY, 150 OP_ADD = OP_BINARY, 151 OP_SUB, 152 OP_MULU, OP_MULS, 153 OP_DIVU, OP_DIVS, 154 OP_MODU, OP_MODS, 155 OP_SHL, 156 OP_LSR, OP_ASR, 157 158 /* Logical */ 159 OP_AND, 160 OP_OR, 161 OP_XOR, 162 OP_AND_BOOL, 163 OP_OR_BOOL, 164 OP_BINARY_END = OP_OR_BOOL, 165 166 /* Binary comparison */ 167 OP_BINCMP, 168 OP_SET_EQ = OP_BINCMP, 169 OP_SET_NE, 170 OP_SET_LE, 171 OP_SET_GE, 172 OP_SET_LT, 173 OP_SET_GT, 174 OP_SET_B, 175 OP_SET_A, 176 OP_SET_BE, 177 OP_SET_AE, 178 OP_BINCMP_END = OP_SET_AE, 179 180 /* Uni */ 181 OP_NOT, 182 OP_NEG, 183 184 /* Select - three input values */ 185 OP_SEL, 186 187 /* Memory */ 188 OP_MALLOC, 189 OP_FREE, 190 OP_ALLOCA, 191 OP_LOAD, 192 OP_STORE, 193 OP_SETVAL, 194 OP_SYMADDR, 195 OP_GET_ELEMENT_PTR, 196 197 /* Other */ 198 OP_PHI, 199 OP_PHISOURCE, 200 OP_CAST, 201 OP_SCAST, 202 OP_FPCAST, 203 OP_PTRCAST, 204 OP_INLINED_CALL, 205 OP_CALL, 206 OP_VANEXT, 207 OP_VAARG, 208 OP_SLICE, 209 OP_SNOP, 210 OP_LNOP, 211 OP_NOP, 212 OP_DEATHNOTE, 213 OP_ASM, 214 215 /* Sparse tagging (line numbers, context, whatever) */ 216 OP_CONTEXT, 217 OP_RANGE, 218 219 /* Needed to translate SSA back to normal form */ 220 OP_COPY, 221 }; 222 223 struct basic_block_list; 224 struct instruction_list; 225 226 struct basic_block { 227 struct position pos; 228 unsigned long generation; 229 int context; 230 struct entrypoint *ep; 231 struct basic_block_list *parents; /* sources */ 232 struct basic_block_list *children; /* destinations */ 233 struct instruction_list *insns; /* Linear list of instructions */ 234 struct pseudo_list *needs, *defines; 235 union { 236 unsigned int nr; /* unique id for label's names */ 237 void *priv; 238 }; 239 }; 240 241 242 static inline void add_bb(struct basic_block_list **list, struct basic_block *bb) 243 { 244 add_ptr_list(list, bb); 245 } 246 247 static inline void add_instruction(struct instruction_list **list, struct instruction *insn) 248 { 249 add_ptr_list(list, insn); 250 } 251 252 static inline void add_multijmp(struct multijmp_list **list, struct multijmp *multijmp) 253 { 254 add_ptr_list(list, multijmp); 255 } 256 257 static inline pseudo_t *add_pseudo(struct pseudo_list **list, pseudo_t pseudo) 258 { 259 return add_ptr_list(list, pseudo); 260 } 261 262 static inline int remove_pseudo(struct pseudo_list **list, pseudo_t pseudo) 263 { 264 return delete_ptr_list_entry((struct ptr_list **)list, pseudo, 0) != 0; 265 } 266 267 static inline int bb_terminated(struct basic_block *bb) 268 { 269 struct instruction *insn; 270 if (!bb) 271 return 0; 272 insn = last_instruction(bb->insns); 273 return insn && insn->opcode >= OP_TERMINATOR 274 && insn->opcode <= OP_TERMINATOR_END; 275 } 276 277 static inline int bb_reachable(struct basic_block *bb) 278 { 279 return bb != NULL; 280 } 281 282 static inline void add_pseudo_ptr(pseudo_t *ptr, struct pseudo_ptr_list **list) 283 { 284 add_ptr_list(list, ptr); 285 } 286 287 static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list) 288 { 289 add_ptr_list(list, user); 290 } 291 292 static inline int has_use_list(pseudo_t p) 293 { 294 return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_VAL); 295 } 296 297 static inline struct pseudo_user *alloc_pseudo_user(struct instruction *insn, pseudo_t *pp) 298 { 299 struct pseudo_user *user = __alloc_pseudo_user(0); 300 user->userp = pp; 301 user->insn = insn; 302 return user; 303 } 304 305 static inline void use_pseudo(struct instruction *insn, pseudo_t p, pseudo_t *pp) 306 { 307 *pp = p; 308 if (has_use_list(p)) 309 add_pseudo_user_ptr(alloc_pseudo_user(insn, pp), &p->users); 310 } 311 312 static inline void remove_bb_from_list(struct basic_block_list **list, struct basic_block *entry, int count) 313 { 314 delete_ptr_list_entry((struct ptr_list **)list, entry, count); 315 } 316 317 static inline void replace_bb_in_list(struct basic_block_list **list, 318 struct basic_block *old, struct basic_block *new, int count) 319 { 320 replace_ptr_list_entry((struct ptr_list **)list, old, new, count); 321 } 322 323 struct entrypoint { 324 struct symbol *name; 325 struct symbol_list *syms; 326 struct pseudo_list *accesses; 327 struct basic_block_list *bbs; 328 struct basic_block *active; 329 struct instruction *entry; 330 }; 331 332 extern void insert_select(struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t if_true, pseudo_t if_false); 333 extern void insert_branch(struct basic_block *bb, struct instruction *br, struct basic_block *target); 334 335 pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, int size); 336 pseudo_t alloc_pseudo(struct instruction *def); 337 pseudo_t value_pseudo(struct symbol *type, long long val); 338 unsigned int value_size(long long value); 339 340 struct entrypoint *linearize_symbol(struct symbol *sym); 341 int unssa(struct entrypoint *ep); 342 void show_entry(struct entrypoint *ep); 343 const char *show_pseudo(pseudo_t pseudo); 344 void show_bb(struct basic_block *bb); 345 const char *show_instruction(struct instruction *insn); 346 347 #endif /* LINEARIZE_H */ 348